Skip to content

feat(plugin): azure serverless functions#5479

Merged
membphis merged 10 commits into
apache:masterfrom
bisakhmondal:azure-functions
Nov 19, 2021
Merged

feat(plugin): azure serverless functions#5479
membphis merged 10 commits into
apache:masterfrom
bisakhmondal:azure-functions

Conversation

@bisakhmondal

@bisakhmondal bisakhmondal commented Nov 10, 2021

Copy link
Copy Markdown
Member

What this PR does / why we need it:

Pre-submission checklist:

  • Did you explain what problem does this PR solve? Or what new features have been added?
  • Have you added corresponding test cases?
  • Have you modified the corresponding document?
  • Is this PR backward compatible? If it is not backward compatible, please discuss on the mailing list first

@bisakhmondal bisakhmondal changed the title feat: azure serverless functions plugin support feat(plugin): azure serverless functions Nov 10, 2021
@bisakhmondal
bisakhmondal marked this pull request as ready for review November 16, 2021 14:36
Comment thread apisix/plugins/azure-functions.lua Outdated
function _M.access(conf, ctx)
local uri_args = core.request.get_uri_args(ctx)
local headers = core.request.headers(ctx) or {}
local req_body, _ = core.request.get_body()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if the request body are large and we cannot load it into memory totally?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The body will be missing when it is larger than client_body_buffer_size (8k by default)
We can read the body by ourselves via ngx.req.socket? See https://github.com/openresty/lua-resty-upload/blob/master/lib/resty/upload.lua

We can do it in the next PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I just realize it uses core.request.get_body, which will read data from file if need. BTW, we should check the err returned by this function.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

thanks for pointing it out @tokers!
@spacewander even if it reads the content from a file, it reads everything in one go

local function get_file(file_name)
local f, err = io_open(file_name, 'r')
if not f then
return nil, err
end
local req_body = f:read("*all")
f:close()
return req_body
end

I think we should use chunked transfer encoding here to proxy the request with a large body size. WDYT?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think normally people don't need to submit big data to azure functions. We can keep this function unchanged for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agree, but it's better to add some hints in the document. @bisakhmondal @spacewander

Comment thread apisix/plugins/azure-functions.lua Outdated
local res, err = httpc:request_uri(conf.function_uri, params)

if not res or err then
return core.response.exit(500, "failed to process azure function, err: " .. err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
return core.response.exit(500, "failed to process azure function, err: " .. err)
core.log.error("failed to process azure function, err: " .. err)
return 503

I think it will be safer not to return an internal error to the client.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ack

Comment thread conf/config-default.yaml Outdated
- response-rewrite # priority: 899
#- dubbo-proxy # priority: 507
- grpc-transcode # priority: 506
- azure-functions # priority: 505

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Better to put it ahead of serverless-post-function

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What should be the priority value, negative?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

priority: -1900?

Comment thread t/plugin/azure-functions.t Outdated
add_block_preprocessor(sub {
my ($block) = @_;

if (!defined $block->additional_http_config) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can use http_config to inject HTTP config, see https://github.com/apache/apisix/blob/master/t/discovery/consul_kv.t

And I suggest you put azure-demo as

function _M.hello()

There is no need to introduce a new server.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Gotcha

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done, Is it okay now?

Comment thread apisix/plugins/azure-functions.lua Outdated
headers["x-functions-key"] = conf.authorization.apikey or ""
headers["x-functions-clientid"] = conf.authorization.clientid or ""
else
headers["x-functions-key"] = getenv(env_key.API)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to expose the AZURE_FUNCTIONS_APIKEY via env AZURE_FUNCTIONS_APIKEY, if this plugin is enabled. Nginx will hide all environment variables by default.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You mean like this env AZURE_FUNCTIONS_APIKEY="key" make run?
Or you are suggesting to update something?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Like

env PATH; # for searching external plugin runner's binary
, but only when this plugin is enabled:
{% if enabled_plugins["proxy-cache"] then %}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I change my mind. Maybe it could be easier to pass this argument via plugin metadata.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Metadata won't be a great fit, IMHO. There might be multiple instances of plugins linked to different routes and we can't force users to use the same key they put into the metadata schema(must be the master key, instead of function-specific keys). This clearly violates principle of Least Access Privileges, isn't it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed env vars and added metadata as a fallback option

method = ngx.req.get_method(),
body = req_body,
query = uri_args,
headers = headers,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need to remove the host header? Otherwise, the host of APISIX will be used.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done, It was the root of many problem.

Comment thread t/plugin/azure-functions.t Outdated
=== TEST 5: http2 check response body and headers
--- http2
--- exec
curl -XGET --http2 --http2-prior-knowledge localhost:1984/azure

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Nice, it is. Updated

Comment thread apisix/plugins/azure-functions.lua Outdated
Comment thread apisix/plugins/azure-functions.lua Outdated
@bzp2010

bzp2010 commented Nov 18, 2021

Copy link
Copy Markdown
Contributor

I have a question, should we standardize the naming of all serverless plugins? such as xxx-function or xxx-serverless 🤔

@spacewander

Copy link
Copy Markdown
Member

@bzp2010
I think we can use the product name directly (azure-functions in this case). It is easier to be searched.

@spacewander
spacewander requested a review from tokers November 19, 2021 00:44
@membphis
membphis merged commit 3a6a4db into apache:master Nov 19, 2021
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.

6 participants