feautre: support for proxy mirror plugin. (#1288)

This commit is contained in:
agile6v 2020-03-19 08:10:03 +08:00 committed by GitHub
parent cee03225f8
commit fc948f9578
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 571 additions and 1 deletions

View File

@ -373,6 +373,7 @@ http {
}
location / {
set $upstream_mirror_host '';
set $upstream_scheme 'http';
set $upstream_host $host;
set $upstream_upgrade '';
@ -444,6 +445,7 @@ http {
{% end %}
proxy_pass $upstream_scheme://apisix_backend$upstream_uri;
mirror /proxy_mirror;
header_filter_by_lua_block {
apisix.http_header_filter_phase()
@ -480,6 +482,16 @@ http {
apisix.http_log_phase()
}
}
location = /proxy_mirror {
internal;
if ($upstream_mirror_host = "") {
return 200;
}
proxy_pass $upstream_mirror_host$request_uri;
}
}
}
]=]

View File

@ -142,6 +142,7 @@ plugins: # plugin list
- wolf-rbac
- proxy-cache
- tcp-logger
- proxy-mirror
stream_plugins:
- mqtt-proxy

View File

@ -60,6 +60,7 @@ Plugins
* [fault-injection](plugins/fault-injection.md): The specified response body, response code, and response time can be returned, which provides processing capabilities in different failure scenarios, such as service failure, service overload, and high service delay.
* [proxy-cache](plugins/proxy-cache.md): Provides the ability to cache upstream response data.
* [tcp-logger](plugins/tcp-logger.md): Log requests to TCP servers
* [proxy-mirror](plugins/proxy-mirror.md): Provides the ability to mirror client requests.
Deploy to the Cloud
=======

View File

@ -60,4 +60,5 @@ Reference document
* [response-rewrite](plugins/response-rewrite-cn.md): 支持自定义修改返回内容的 `status code`、`body`、`headers`。
* [fault-injection](plugins/fault-injection-cn.md):故障注入,可以返回指定的响应体、响应码和响应时间,从而提供了不同的失败场景下处理的能力,例如服务失败、服务过载、服务高延时等。
* [proxy-cache](plugins/proxy-cache-cn.md):代理缓存插件提供缓存后端响应数据的能力。
* [proxy-mirror](plugins/proxy-mirror-cn.md):代理镜像插件提供镜像客户端请求的能力。

View File

@ -0,0 +1,93 @@
<!--
#
# 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.
#
-->
[English](proxy-mirror.md)
# proxy-mirror
代理镜像插件,该插件提供了镜像客户端请求的能力。
注:镜像请求返回的响应会被忽略。
### 参数
|名称 |必须|类型|描述|
|------- |-----|------|------|
|host|是|string|指定镜像服务地址例如http://127.0.0.1:9797地址中需要包含 schema http或https不能包含 URI 部分)|
### 示例
#### 启用插件
示例1为特定路由启用 `proxy-mirror` 插件:
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1:9797"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1999": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
测试:
```shell
$ curl http://127.0.0.1:9080/hello -i
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 12
Connection: keep-alive
Server: APISIX web server
Date: Wed, 18 Mar 2020 13:01:11 GMT
Last-Modified: Thu, 20 Feb 2020 14:21:41 GMT
hello world
```
> 由于指定的 mirror 地址是127.0.0.1:9797所以验证此插件是否已经正常工作需要在端口为9797的服务上确认例如我们可以通过 python 启动一个简单的 server python -m SimpleHTTPServer 9797。
#### 禁用插件
移除插件配置中相应的 JSON 配置可立即禁用该插件,无需重启服务:
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1999": 1
}
}
}'
```
这时该插件已被禁用。

View File

@ -0,0 +1,97 @@
<!--
#
# 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.
#
-->
[Chinese](proxy-mirror-cn.md)
# proxy-mirror
The proxy-mirror plugin, which provides the ability to mirror client requests.
*Note*: The response returned by the mirror request is ignored.
## Attributes
|Name |Requirement | Type |Description|
|------- |-----|------|------|
|host|required|string|Specify a mirror service address, e.g. http://127.0.0.1:9797 (address needs to contain schema: http or https, not URI part)|
### Examples
#### Enable the plugin
1: enable the proxy-mirror plugin for a specific route :
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1:9797"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1999": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}'
```
Test plugin
```shell
$ curl http://127.0.0.1:9080/hello -i
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 12
Connection: keep-alive
Server: APISIX web server
Date: Wed, 18 Mar 2020 13:01:11 GMT
Last-Modified: Thu, 20 Feb 2020 14:21:41 GMT
hello world
```
> Since the specified mirror address is 127.0.0.1:9797, so to verify whether this plugin is in effect, we need to confirm on the service with port 9797.
> For example, we can start a simple server: python -m SimpleHTTPServer 9797
## Disable Plugin
Remove the corresponding JSON in the plugin configuration to disable the plugin immediately without restarting the service:
```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -X PUT -d '
{
"uri": "/hello",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1999": 1
}
}
}'
```
The plugin has been disabled now.

View File

@ -48,6 +48,8 @@ do
upstream_connection = true,
upstream_uri = true,
upstream_mirror_host = true,
upstream_cache_zone = true,
upstream_cache_zone_info = true,
upstream_no_cache = true,

View File

@ -0,0 +1,59 @@
--
-- 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.
--
local core = require("apisix.core")
local plugin_name = "proxy-mirror"
local schema = {
type = "object",
properties = {
host = {
type = "string",
pattern = [[^http(s)?:\/\/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}]]
.. [[(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:[0-9]{1,5})?$]],
},
},
required = {"host"},
minProperties = 1,
}
local _M = {
version = 0.1,
priority = 1010,
name = plugin_name,
schema = schema,
}
function _M.check_schema(conf)
local ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end
return true
end
function _M.rewrite(conf, ctx)
core.log.info("proxy mirror plugin rewrite phase, conf: ", core.json.delay_encode(conf))
ctx.var.upstream_mirror_host = conf.host
end
return _M

12
t/APISIX.pm vendored
View File

@ -263,6 +263,7 @@ _EOC_
}
location / {
set \$upstream_mirror_host '';
set \$upstream_scheme 'http';
set \$upstream_host \$host;
set \$upstream_upgrade '';
@ -306,6 +307,7 @@ _EOC_
proxy_pass_header Server;
proxy_pass_header Date;
proxy_pass \$upstream_scheme://apisix_backend\$upstream_uri;
mirror /proxy_mirror;
header_filter_by_lua_block {
apisix.http_header_filter_phase()
@ -341,6 +343,16 @@ _EOC_
apisix.http_log_phase()
}
}
location = /proxy_mirror {
internal;
if (\$upstream_mirror_host = "") {
return 200;
}
proxy_pass \$upstream_mirror_host\$request_uri;
}
_EOC_
$block->set_value("config", $config);

View File

@ -30,7 +30,7 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger"\]/
qr/\["limit-req","limit-count","limit-conn","key-auth","basic-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect","proxy-rewrite","redirect","response-rewrite","fault-injection","udp-logger","wolf-rbac","proxy-cache","tcp-logger","proxy-mirror"\]/
--- no_error_log
[error]

View File

@ -63,6 +63,7 @@ loaded plugin and sort by priority: 2555 name: wolf-rbac
loaded plugin and sort by priority: 2520 name: basic-auth
loaded plugin and sort by priority: 2510 name: jwt-auth
loaded plugin and sort by priority: 2500 name: key-auth
loaded plugin and sort by priority: 1010 name: proxy-mirror
loaded plugin and sort by priority: 1009 name: proxy-cache
loaded plugin and sort by priority: 1008 name: proxy-rewrite
loaded plugin and sort by priority: 1003 name: limit-conn

291
t/plugin/proxy-mirror.t Normal file
View File

@ -0,0 +1,291 @@
#
# 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_shuffle();
no_root_location();
log_level('info');
add_block_preprocessor(sub {
my ($block) = @_;
my $http_config = $block->http_config // <<_EOC_;
server {
listen 1986;
server_tokens off;
location / {
content_by_lua_block {
ngx.log(ngx.ERR, "uri: ", ngx.var.uri)
ngx.say("hello world")
}
}
}
_EOC_
$block->set_value("http_config", $http_config);
});
run_tests;
__DATA__
=== TEST 1: sanity check (invalid schema)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "ftp://127.0.0.1:1999"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/failed to check the configuration of plugin proxy-mirror/
--- no_error_log
[error]
=== TEST 2: sanity check (invalid port format)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1::1999"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/failed to check the configuration of plugin proxy-mirror/
--- no_error_log
[error]
=== TEST 3: sanity check (without schema)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "127.0.0.1:1999"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/failed to check the configuration of plugin proxy-mirror/
--- no_error_log
[error]
=== TEST 4: sanity check (without port)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 200
--- response_body
passed
--- no_error_log
[error]
=== TEST 4: sanity check (include uri)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1:1999/invalid_uri"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 400
--- response_body eval
qr/failed to check the configuration of plugin proxy-mirror/
--- no_error_log
[error]
=== TEST 5: sanity check (normal case)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"proxy-mirror": {
"host": "http://127.0.0.1:1986"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- error_code: 200
--- response_body
passed
--- no_error_log
[error]
=== TEST 6: hit route
--- request
GET /hello
--- error_code: 200
--- response_body
hello world
--- error_log
uri: /hello