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(ext-plugin): support ExtraInfo #4835

Merged
merged 4 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apisix/constants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ return {
RPC_ERROR = 0,
RPC_PREPARE_CONF = 1,
RPC_HTTP_REQ_CALL = 2,
RPC_EXTRA_INFO = 3,
HTTP_ETCD_DIRECTORY = {
["/upstreams"] = true,
["/plugins"] = true,
Expand Down
67 changes: 63 additions & 4 deletions apisix/plugins/ext-plugin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
local http_req_call_action = require("A6.HTTPReqCall.Action")
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
local extra_info = require("A6.ExtraInfo.Info")
local extra_info_req = require("A6.ExtraInfo.Req")
local extra_info_var = require("A6.ExtraInfo.Var")
local extra_info_resp = require("A6.ExtraInfo.Resp")
local text_entry = require("A6.TextEntry")
local err_resp = require("A6.Err.Resp")
local err_code = require("A6.Err.Code")
Expand Down Expand Up @@ -55,6 +59,7 @@ local str_sub = string.sub
local error = error
local ipairs = ipairs
local pairs = pairs
local tostring = tostring
local type = type


Expand Down Expand Up @@ -251,6 +256,43 @@ local function build_headers(var, builder, key, val)
end


local function handle_extra_info(ctx, input)
-- exact request
local buf = flatbuffers.binaryArray.New(input)
local req = extra_info_req.GetRootAsReq(buf, 0)

local res
local info_type = req:InfoType()
if info_type == extra_info.Var then
local info = req:Info()
local var_req = extra_info_var.New()
var_req:Init(info.bytes, info.pos)

local var_name = var_req:Name()
res = ctx.var[var_name]
else
return nil, "unsupported info type: " .. info_type
end

-- build response
builder:Clear()

local packed_res
if res then
-- ensure to pass the res in string type
res = tostring(res)
packed_res = builder:CreateByteVector(res)
end
extra_info_resp.Start(builder)
if packed_res then
extra_info_resp.AddResult(builder, packed_res)
end
local resp = extra_info_resp.End(builder)
builder:Finish(resp)
return builder:Output()
end


local rpc_call
local rpc_handlers = {
nil,
Expand Down Expand Up @@ -339,7 +381,7 @@ local rpc_handlers = {
local path = builder:CreateString(uri)

local bin_addr = var.binary_remote_addr
local src_ip = builder.CreateByteVector(builder, bin_addr)
local src_ip = builder:CreateByteVector(bin_addr)

local args = core.request.get_uri_args(ctx)
local textEntries = {}
Expand Down Expand Up @@ -400,9 +442,26 @@ local rpc_handlers = {
return nil, "failed to send RPC_HTTP_REQ_CALL: " .. err
end

local ty, resp = receive(sock)
if ty == nil then
return nil, "failed to receive RPC_HTTP_REQ_CALL: " .. resp
local ty, resp
while true do
ty, resp = receive(sock)
if ty == nil then
return nil, "failed to receive RPC_HTTP_REQ_CALL: " .. resp
end

if ty ~= constants.RPC_EXTRA_INFO then
break
end

local out, err = handle_extra_info(ctx, resp)
if not out then
return nil, "failed to handle RPC_EXTRA_INFO: " .. err
end

local ok, err = send(sock, constants.RPC_EXTRA_INFO, out)
if not ok then
return nil, "failed to reply RPC_EXTRA_INFO: " .. err
end
end
shuaijinchao marked this conversation as resolved.
Show resolved Hide resolved

if ty ~= constants.RPC_HTTP_REQ_CALL then
Expand Down
2 changes: 1 addition & 1 deletion rockspec/apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dependencies = {
"luasec = 0.9-1",
"lua-resty-consul = 0.3-2",
"penlight = 1.9.2-1",
"ext-plugin-proto = 0.2.1",
"ext-plugin-proto = 0.3.0",
"casbin = 1.26.0",
"api7-snowflake = 2.0-1",
}
Expand Down
49 changes: 49 additions & 0 deletions t/lib/ext-plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,23 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
local http_req_call_action = require("A6.HTTPReqCall.Action")
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
local extra_info = require("A6.ExtraInfo.Info")
local extra_info_req = require("A6.ExtraInfo.Req")
local extra_info_var = require("A6.ExtraInfo.Var")
local extra_info_resp = require("A6.ExtraInfo.Resp")


local _M = {}
local builder = flatbuffers.Builder(0)


local function build_extra_info(info, ty)
extra_info_req.Start(builder)
extra_info_req.AddInfoType(builder, ty)
extra_info_req.AddInfo(builder, info)
end


local function build_action(action, ty)
http_req_call_resp.Start(builder)
http_req_call_resp.AddActionType(builder, ty)
Expand Down Expand Up @@ -162,6 +173,44 @@ function _M.go(case)
assert(call_req:Method() == a6_method.GET)
end

if case.extra_info then
for _, action in ipairs(case.extra_info) do
if action.type == "closed" then
ngx.exit(-1)
return
end

if action.type == "var" then
local name = builder:CreateString(action.name)
extra_info_var.Start(builder)
extra_info_var.AddName(builder, name)
local var_req = extra_info_var.End(builder)
build_extra_info(var_req, extra_info.Var)
local req = extra_info_req.End(builder)
builder:Finish(req)
data = builder:Output()
local ok, err = ext.send(sock, constants.RPC_EXTRA_INFO, data)
if not ok then
ngx.log(ngx.ERR, err)
return
end
ngx.log(ngx.WARN, "send extra info req successfully")

local ty, data = ext.receive(sock)
if not ty then
ngx.log(ngx.ERR, data)
return
end

assert(ty == constants.RPC_EXTRA_INFO, ty)
local buf = flatbuffers.binaryArray.New(data)
local resp = extra_info_resp.GetRootAsResp(buf, 0)
local res = resp:ResultAsString()
assert(res == action.result, res)
end
end
end

if case.stop == true then
local len = 3
http_req_call_stop.StartBodyVector(builder, len)
Expand Down
183 changes: 183 additions & 0 deletions t/plugin/ext-plugin/extra-info.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#
# 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.
#
use t::APISIX 'no_plan';

repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();

add_block_preprocessor(sub {
my ($block) = @_;

$block->set_value("stream_conf_enable", 1);

if (!defined $block->extra_stream_config) {
my $stream_config = <<_EOC_;
server {
listen unix:\$TEST_NGINX_HTML_DIR/nginx.sock;

content_by_lua_block {
local ext = require("lib.ext-plugin")
ext.go({})
}
}

_EOC_
$block->set_value("extra_stream_config", $stream_config);
}

my $unix_socket_path = $ENV{"TEST_NGINX_HTML_DIR"} . "/nginx.sock";
my $cmd = $block->ext_plugin_cmd // "['sleep', '5s']";
my $extra_yaml_config = <<_EOC_;
ext-plugin:
path_for_test: $unix_socket_path
cmd: $cmd
_EOC_

$block->set_value("extra_yaml_config", $extra_yaml_config);

if (!$block->request) {
$block->set_value("request", "GET /t");
}

if (!$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});

run_tests;

__DATA__

=== TEST 1: add route
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin")

local code, message, res = t.test('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/hello",
"plugins": {
"ext-plugin-pre-req": {
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)

if code >= 300 then
ngx.status = code
ngx.say(message)
return
end

ngx.say(message)
}
}
--- response_body
passed



=== TEST 2: var
--- request
GET /hello?x=
--- extra_stream_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;

content_by_lua_block {
local ext = require("lib.ext-plugin")
local actions = {
{type = "var", name = "server_addr", result = "127.0.0.1"},
{type = "var", name = "remote_addr", result = "127.0.0.1"},
{type = "var", name = "route_id", result = "1"},
{type = "var", name = "arg_x", result = ""},
}
ext.go({extra_info = actions, stop = true})
}
}
--- error_code: 405
--- grep_error_log eval
qr/send extra info req successfully/
--- grep_error_log_out
send extra info req successfully
send extra info req successfully
send extra info req successfully
send extra info req successfully



=== TEST 3: ask nonexistent var
--- request
GET /hello
--- more_headers
X-Change: foo
X-Delete: foo
--- extra_stream_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;

content_by_lua_block {
local ext = require("lib.ext-plugin")
local actions = {
{type = "var", name = "erver_addr"},
}
ext.go({extra_info = actions, rewrite = true})
}
}
--- response_body
uri: /uri
host: localhost
x-add: bar
x-change: bar
x-real-ip: 127.0.0.1
--- grep_error_log eval
qr/send extra info req successfully/
--- grep_error_log_out
send extra info req successfully



=== TEST 4: network is down in the middle
--- request
GET /hello
--- extra_stream_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;

content_by_lua_block {
local ext = require("lib.ext-plugin")
local actions = {
{type = "var", name = "server_addr", result = "127.0.0.1"},
{type = "closed"},
}
ext.go({extra_info = actions, stop = true})
}
}
--- error_code: 503
--- error_log
failed to receive RPC_HTTP_REQ_CALL: closed