Skip to content

Commit b72404f

Browse files
authored
feat(ext-plugin): support ExtraInfo (#4835)
* feat(ext-plugin): support ExtraInfo Signed-off-by: spacewander <[email protected]> * ensure to use str Signed-off-by: spacewander <[email protected]> * fix test Signed-off-by: spacewander <[email protected]> * ws Signed-off-by: spacewander <[email protected]>
1 parent b0246c8 commit b72404f

File tree

5 files changed

+297
-5
lines changed

5 files changed

+297
-5
lines changed

apisix/constants.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ return {
1818
RPC_ERROR = 0,
1919
RPC_PREPARE_CONF = 1,
2020
RPC_HTTP_REQ_CALL = 2,
21+
RPC_EXTRA_INFO = 3,
2122
HTTP_ETCD_DIRECTORY = {
2223
["/upstreams"] = true,
2324
["/plugins"] = true,

apisix/plugins/ext-plugin/init.lua

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
2424
local http_req_call_action = require("A6.HTTPReqCall.Action")
2525
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
2626
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
27+
local extra_info = require("A6.ExtraInfo.Info")
28+
local extra_info_req = require("A6.ExtraInfo.Req")
29+
local extra_info_var = require("A6.ExtraInfo.Var")
30+
local extra_info_resp = require("A6.ExtraInfo.Resp")
2731
local text_entry = require("A6.TextEntry")
2832
local err_resp = require("A6.Err.Resp")
2933
local err_code = require("A6.Err.Code")
@@ -54,6 +58,7 @@ local str_sub = string.sub
5458
local error = error
5559
local ipairs = ipairs
5660
local pairs = pairs
61+
local tostring = tostring
5762
local type = type
5863

5964

@@ -250,6 +255,43 @@ local function build_headers(var, builder, key, val)
250255
end
251256

252257

258+
local function handle_extra_info(ctx, input)
259+
-- exact request
260+
local buf = flatbuffers.binaryArray.New(input)
261+
local req = extra_info_req.GetRootAsReq(buf, 0)
262+
263+
local res
264+
local info_type = req:InfoType()
265+
if info_type == extra_info.Var then
266+
local info = req:Info()
267+
local var_req = extra_info_var.New()
268+
var_req:Init(info.bytes, info.pos)
269+
270+
local var_name = var_req:Name()
271+
res = ctx.var[var_name]
272+
else
273+
return nil, "unsupported info type: " .. info_type
274+
end
275+
276+
-- build response
277+
builder:Clear()
278+
279+
local packed_res
280+
if res then
281+
-- ensure to pass the res in string type
282+
res = tostring(res)
283+
packed_res = builder:CreateByteVector(res)
284+
end
285+
extra_info_resp.Start(builder)
286+
if packed_res then
287+
extra_info_resp.AddResult(builder, packed_res)
288+
end
289+
local resp = extra_info_resp.End(builder)
290+
builder:Finish(resp)
291+
return builder:Output()
292+
end
293+
294+
253295
local rpc_call
254296
local rpc_handlers = {
255297
nil,
@@ -338,7 +380,7 @@ local rpc_handlers = {
338380
local path = builder:CreateString(uri)
339381

340382
local bin_addr = var.binary_remote_addr
341-
local src_ip = builder.CreateByteVector(builder, bin_addr)
383+
local src_ip = builder:CreateByteVector(bin_addr)
342384

343385
local args = core.request.get_uri_args(ctx)
344386
local textEntries = {}
@@ -399,9 +441,26 @@ local rpc_handlers = {
399441
return nil, "failed to send RPC_HTTP_REQ_CALL: " .. err
400442
end
401443

402-
local ty, resp = receive(sock)
403-
if ty == nil then
404-
return nil, "failed to receive RPC_HTTP_REQ_CALL: " .. resp
444+
local ty, resp
445+
while true do
446+
ty, resp = receive(sock)
447+
if ty == nil then
448+
return nil, "failed to receive RPC_HTTP_REQ_CALL: " .. resp
449+
end
450+
451+
if ty ~= constants.RPC_EXTRA_INFO then
452+
break
453+
end
454+
455+
local out, err = handle_extra_info(ctx, resp)
456+
if not out then
457+
return nil, "failed to handle RPC_EXTRA_INFO: " .. err
458+
end
459+
460+
local ok, err = send(sock, constants.RPC_EXTRA_INFO, out)
461+
if not ok then
462+
return nil, "failed to reply RPC_EXTRA_INFO: " .. err
463+
end
405464
end
406465

407466
if ty ~= constants.RPC_HTTP_REQ_CALL then

rockspec/apisix-master-0.rockspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ dependencies = {
6666
"luasec = 0.9-1",
6767
"lua-resty-consul = 0.3-2",
6868
"penlight = 1.9.2-1",
69-
"ext-plugin-proto = 0.2.1",
69+
"ext-plugin-proto = 0.3.0",
7070
"casbin = 1.26.0",
7171
"api7-snowflake = 2.0-1",
7272
}

t/lib/ext-plugin.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,23 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
2929
local http_req_call_action = require("A6.HTTPReqCall.Action")
3030
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
3131
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
32+
local extra_info = require("A6.ExtraInfo.Info")
33+
local extra_info_req = require("A6.ExtraInfo.Req")
34+
local extra_info_var = require("A6.ExtraInfo.Var")
35+
local extra_info_resp = require("A6.ExtraInfo.Resp")
3236

3337

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

3741

42+
local function build_extra_info(info, ty)
43+
extra_info_req.Start(builder)
44+
extra_info_req.AddInfoType(builder, ty)
45+
extra_info_req.AddInfo(builder, info)
46+
end
47+
48+
3849
local function build_action(action, ty)
3950
http_req_call_resp.Start(builder)
4051
http_req_call_resp.AddActionType(builder, ty)
@@ -162,6 +173,44 @@ function _M.go(case)
162173
assert(call_req:Method() == a6_method.GET)
163174
end
164175

176+
if case.extra_info then
177+
for _, action in ipairs(case.extra_info) do
178+
if action.type == "closed" then
179+
ngx.exit(-1)
180+
return
181+
end
182+
183+
if action.type == "var" then
184+
local name = builder:CreateString(action.name)
185+
extra_info_var.Start(builder)
186+
extra_info_var.AddName(builder, name)
187+
local var_req = extra_info_var.End(builder)
188+
build_extra_info(var_req, extra_info.Var)
189+
local req = extra_info_req.End(builder)
190+
builder:Finish(req)
191+
data = builder:Output()
192+
local ok, err = ext.send(sock, constants.RPC_EXTRA_INFO, data)
193+
if not ok then
194+
ngx.log(ngx.ERR, err)
195+
return
196+
end
197+
ngx.log(ngx.WARN, "send extra info req successfully")
198+
199+
local ty, data = ext.receive(sock)
200+
if not ty then
201+
ngx.log(ngx.ERR, data)
202+
return
203+
end
204+
205+
assert(ty == constants.RPC_EXTRA_INFO, ty)
206+
local buf = flatbuffers.binaryArray.New(data)
207+
local resp = extra_info_resp.GetRootAsResp(buf, 0)
208+
local res = resp:ResultAsString()
209+
assert(res == action.result, res)
210+
end
211+
end
212+
end
213+
165214
if case.stop == true then
166215
local len = 3
167216
http_req_call_stop.StartBodyVector(builder, len)

t/plugin/ext-plugin/extra-info.t

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
use t::APISIX 'no_plan';
18+
19+
repeat_each(1);
20+
no_long_string();
21+
no_root_location();
22+
no_shuffle();
23+
24+
add_block_preprocessor(sub {
25+
my ($block) = @_;
26+
27+
$block->set_value("stream_conf_enable", 1);
28+
29+
if (!defined $block->extra_stream_config) {
30+
my $stream_config = <<_EOC_;
31+
server {
32+
listen unix:\$TEST_NGINX_HTML_DIR/nginx.sock;
33+
34+
content_by_lua_block {
35+
local ext = require("lib.ext-plugin")
36+
ext.go({})
37+
}
38+
}
39+
40+
_EOC_
41+
$block->set_value("extra_stream_config", $stream_config);
42+
}
43+
44+
my $unix_socket_path = $ENV{"TEST_NGINX_HTML_DIR"} . "/nginx.sock";
45+
my $cmd = $block->ext_plugin_cmd // "['sleep', '5s']";
46+
my $extra_yaml_config = <<_EOC_;
47+
ext-plugin:
48+
path_for_test: $unix_socket_path
49+
cmd: $cmd
50+
_EOC_
51+
52+
$block->set_value("extra_yaml_config", $extra_yaml_config);
53+
54+
if (!$block->request) {
55+
$block->set_value("request", "GET /t");
56+
}
57+
58+
if (!$block->error_log) {
59+
$block->set_value("no_error_log", "[error]\n[alert]");
60+
}
61+
});
62+
63+
run_tests;
64+
65+
__DATA__
66+
67+
=== TEST 1: add route
68+
--- config
69+
location /t {
70+
content_by_lua_block {
71+
local json = require("toolkit.json")
72+
local t = require("lib.test_admin")
73+
74+
local code, message, res = t.test('/apisix/admin/routes/1',
75+
ngx.HTTP_PUT,
76+
[[{
77+
"uri": "/hello",
78+
"plugins": {
79+
"ext-plugin-pre-req": {
80+
}
81+
},
82+
"upstream": {
83+
"nodes": {
84+
"127.0.0.1:1980": 1
85+
},
86+
"type": "roundrobin"
87+
}
88+
}]]
89+
)
90+
91+
if code >= 300 then
92+
ngx.status = code
93+
ngx.say(message)
94+
return
95+
end
96+
97+
ngx.say(message)
98+
}
99+
}
100+
--- response_body
101+
passed
102+
103+
104+
105+
=== TEST 2: var
106+
--- request
107+
GET /hello?x=
108+
--- extra_stream_config
109+
server {
110+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
111+
112+
content_by_lua_block {
113+
local ext = require("lib.ext-plugin")
114+
local actions = {
115+
{type = "var", name = "server_addr", result = "127.0.0.1"},
116+
{type = "var", name = "remote_addr", result = "127.0.0.1"},
117+
{type = "var", name = "route_id", result = "1"},
118+
{type = "var", name = "arg_x", result = ""},
119+
}
120+
ext.go({extra_info = actions, stop = true})
121+
}
122+
}
123+
--- error_code: 405
124+
--- grep_error_log eval
125+
qr/send extra info req successfully/
126+
--- grep_error_log_out
127+
send extra info req successfully
128+
send extra info req successfully
129+
send extra info req successfully
130+
send extra info req successfully
131+
132+
133+
134+
=== TEST 3: ask nonexistent var
135+
--- request
136+
GET /hello
137+
--- more_headers
138+
X-Change: foo
139+
X-Delete: foo
140+
--- extra_stream_config
141+
server {
142+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
143+
144+
content_by_lua_block {
145+
local ext = require("lib.ext-plugin")
146+
local actions = {
147+
{type = "var", name = "erver_addr"},
148+
}
149+
ext.go({extra_info = actions, rewrite = true})
150+
}
151+
}
152+
--- response_body
153+
uri: /uri
154+
host: localhost
155+
x-add: bar
156+
x-change: bar
157+
x-real-ip: 127.0.0.1
158+
--- grep_error_log eval
159+
qr/send extra info req successfully/
160+
--- grep_error_log_out
161+
send extra info req successfully
162+
163+
164+
165+
=== TEST 4: network is down in the middle
166+
--- request
167+
GET /hello
168+
--- extra_stream_config
169+
server {
170+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
171+
172+
content_by_lua_block {
173+
local ext = require("lib.ext-plugin")
174+
local actions = {
175+
{type = "var", name = "server_addr", result = "127.0.0.1"},
176+
{type = "closed"},
177+
}
178+
ext.go({extra_info = actions, stop = true})
179+
}
180+
}
181+
--- error_code: 503
182+
--- error_log
183+
failed to receive RPC_HTTP_REQ_CALL: closed

0 commit comments

Comments
 (0)