Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugins) AWS Lambda plugin #1777

Merged
merged 10 commits into from
Dec 28, 2016
Merged

feat(plugins) AWS Lambda plugin #1777

merged 10 commits into from
Dec 28, 2016

Conversation

subnetmarco
Copy link
Member

@subnetmarco subnetmarco commented Oct 27, 2016

AWS Lambda support.

Closes #1005, and #1190 from which it is heavily inspired (by @timerickson).

@sonicaghi
Copy link
Member

On the plugin gallery we now have to create a new category called: Serverless

["X-Amz-Invocation-Type"] = conf.invocation_type,
["X-Amx-Log-Type"] = conf.log_type,
["Content-Type"] = "application/x-amz-json-1.1",
["Content-Length"] = tostring(string.len(bodyJson))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use the len method, just use tostring(#bodyJson)

local bodyJson = cjson.encode(retrieve_parameters())

local host = string.format("lambda.%s.amazonaws.com", conf.aws_region)
local path = string.format("/2015-03-31/functions/%s/invocations",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the aws lambda stuff, but are these literals here intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

["kong.plugins.aws-lambda.handler"] = "kong/plugins/aws-lambda/handler.lua",
["kong.plugins.aws-lambda.schema"] = "kong/plugins/aws-lambda/schema.lua",
["kong.plugins.aws-lambda.access"] = "kong/plugins/aws-lambda/access.lua",
["kong.plugins.aws-lambda.v4"] = "kong/plugins/aws-lambda/v4.lua"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use trailing comma for table costructors


AWSLambdaHandler.PRIORITY = 750

return AWSLambdaHandler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge the access.lua file with this one, no use in multiple files here

aws_secret = {type = "string", required = true},
aws_region = {type = "string", required = true, enum = {
"us-east-1", "us-east-2", "ap-northeast-1", "ap-northeast-2",
"ap-southeast-1", "ap-southeast-2", "eu-central-1", "eu-west-1"}},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want those to be literals? requires maintenance when amazon decides to change things

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for now I would keep it like this - we can always change it in the future

for name, value in pairs(headers) do
if value then -- ignore headers with 'false', they are used to override defaults
i = i + 1
local name_lower = name:lower()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using lower here, while just above we're using upper on a first glance not efficient

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the upper.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 144

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's line 140 now, where it is commented as -- convert to standard header title case

}
end

return prepare_awsv4_request
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general; lots of locals to cache; from string and table, and then some

method = request_method;
target = target;
headers = headers;
body = req_payload;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use ;, use ,

@@ -95,7 +95,7 @@ local function send_response(status_code)
-- @see https://github.com/openresty/lua-nginx-module
-- @param content (Optional) The content to send as a response.
-- @return ngx.exit (Exit current context)
return function(content, headers)
return function(content, headers, raw_body)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update comments for the extra parameter

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this have to do with this the aws-lambda plugin?

@@ -144,14 +146,14 @@ local closure_cache = {}
-- @param body A string or table which will be the body of the sent response. If table, the response will be encoded as a JSON object. If string, the response will be a JSON object and the string will be contained in the `message` property.
-- @param[type=table] headers Response headers to send.
-- @return ngx.exit (Exit current context)
function _M.send(status_code, body, headers)
function _M.send(status_code, body, headers, raw_body)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update comments for extra parameter

end

local function hex_encode(str) -- From prosody's util.hex
local char_to_hex = {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This char_to_hex table is a constant, filled right below. This one must move outside the scope (top of module?) or it will regenerate the table on every invocation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@Tieske
Copy link
Member

Tieske commented Nov 16, 2016

also; missing integration tests.

@subnetmarco
Copy link
Member Author

@Tieske tests in the 01-access_spec.lua file.

@subnetmarco subnetmarco force-pushed the feat/plugin-lambda branch 2 times, most recently from b352494 to e32d94d Compare November 19, 2016 01:08
@@ -1,14 +1,15 @@
return {
fields = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this have to do with the aws-lambda plugin?

@timerickson
Copy link

timerickson commented Nov 20, 2016

Why does this drop the support of IAM Instance Role authentication that was in #1190 ?

@timerickson
Copy link

Why does this drop the the support for implicit configuration (via parsed aws-lambda:// url definition) that was in #1190 ?

@timerickson
Copy link

What is the explanation/expectation of behavior when specifying anything other than RequestResponse invocation_type? It is undefined, and that is why it was left off #1190 .

@timerickson
Copy link

Why does this drop support for supplying IAM credentials in the Authorization header as had been in #1190 ?

@timerickson
Copy link

This does not appear to have proper error handling as was in #1190 . On error, AWS Lambda returns a 200 with a response header indicating the presence of the error. Lambda execution is essentially RPC not restful.

@subnetmarco
Copy link
Member Author

subnetmarco commented Nov 21, 2016

Why does this drop the support of IAM Instance Role authentication that was in #1190 ?

The older implementation is blocking and needs to be rewritten with a non-blocking cosocket API. It is missing in this PR and it just has to be done.

Why does this drop the the support for implicit configuration (via parsed aws-lambda:// url definition) that was in #1190 ?

Looking at the big picture it seems like Kong will have two kind of routes: proxy routes, and functional routes that don't proxy to anything but expect a plugin to take over and return a response (like this plugin). We can start discussing about this so we can properly support all those future plugins that return a response without proxying it to an upstream. Also, the previous implementation was changing the core, breaking the core/plugin separation. A better internal API is needed instead.

What is the explanation/expectation of behavior when specifying anything other than RequestResponse invocation_type? It is undefined, and that is why it was left off #1190 .

I have added some more tests that show the usage of the other invocation types. Basically the behavior of the plugin is that it invokes the Lambda function with the specified type and returns whatever response Lambda returns.

Why does this drop support for supplying IAM credentials in the Authorization header as had been in #1190 ?

Because the user might want to add other plugins on top of the Lambda plugin that might conflict with the Authorization header: ie, if I want to protect the Lambda function with Basic Authentication. Another header could be used, but what's the use-case of being able to dynamically set the AWS credentials? Can't that be done by applying the plugin multiple times per different user, each one of them with different credentials?

This does not appear to have proper error handling as was in #1190 . On error, AWS Lambda returns a 200 with a response header indicating the presence of the error. Lambda execution is essentially RPC not restful.

The plugin returns the response the same way Lambda returns it. I didn't change the response being returned by Lambda, because I don't think the plugin should do it. The user can refer to the Lambda documentation to understand how to handle the response. Thoughts?

@subnetmarco
Copy link
Member Author

On a second though this plugin should also be using content_by_lua so we can properly handle response and Log plugins on top of it.

@thibaultcha
Copy link
Member

On a second though this plugin should also be using content_by_lua so we can properly handle response and Log plugins on top of it.

As we know though, only one content handler must be provided per location in Nginx, and thus proxy_pass and content_by_lua conflicts if used together.

@subnetmarco
Copy link
Member Author

subnetmarco commented Dec 10, 2016

proxy_pass and content_by_lua conflicts if used together

I am just brainstorming, but maybe we could leverage ngx.exec to accomplish our task with an internal redirect, ie (pseudo-code):

worker_processes auto;
error_log logs/error.log info;
daemon off;

events {
  worker_connections 1024;
}

http {
  server {
    listen 9000;

    location @proxy {
      internal;
      proxy_pass http://httpbin.org;
    }

    location / {
      content_by_lua '
        local content_handler = plugin.handler.content
        if content_handler then
          content_handler()
        else
          return ngx.exec("@proxy")
        end
      ';
    }
  }

}

Although it seems like ngx.exec doesn't not allow to share nginx variables or ctx variables, and this may be a problem.

@subnetmarco subnetmarco merged commit ef52403 into next Dec 28, 2016
@subnetmarco subnetmarco deleted the feat/plugin-lambda branch December 28, 2016 23:55
@shavo007
Copy link

@sonicaghi "On the plugin gallery we now have to create a new category called: Serverless"

Where is this defined in the doc?

I do not see it here:
https://getkong.org/plugins/

@subnetmarco
Copy link
Member Author

@shavo007 coming soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants