You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2020/03/19 00:10:12 UTC
[incubator-apisix] branch master updated: feautre: support for
proxy mirror plugin. (#1288)
This is an automated email from the ASF dual-hosted git repository.
wenming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-apisix.git
The following commit(s) were added to refs/heads/master by this push:
new fc948f9 feautre: support for proxy mirror plugin. (#1288)
fc948f9 is described below
commit fc948f95787240d56cfd933b320e121adf7bef2c
Author: agile6v <ag...@agile6v.com>
AuthorDate: Thu Mar 19 08:10:03 2020 +0800
feautre: support for proxy mirror plugin. (#1288)
---
bin/apisix | 12 ++
conf/config.yaml | 1 +
doc/README.md | 1 +
doc/README_CN.md | 1 +
doc/plugins/proxy-mirror-cn.md | 93 ++++++++++++
doc/plugins/proxy-mirror.md | 97 ++++++++++++
lua/apisix/core/ctx.lua | 2 +
lua/apisix/plugins/proxy-mirror.lua | 59 ++++++++
t/APISIX.pm | 12 ++
t/admin/plugins.t | 2 +-
t/debug/debug-mode.t | 1 +
t/plugin/proxy-mirror.t | 291 ++++++++++++++++++++++++++++++++++++
12 files changed, 571 insertions(+), 1 deletion(-)
diff --git a/bin/apisix b/bin/apisix
index 78c2914..6f0a0f1 100755
--- a/bin/apisix
+++ b/bin/apisix
@@ -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;
+ }
}
}
]=]
diff --git a/conf/config.yaml b/conf/config.yaml
index e050092..65f79da 100644
--- a/conf/config.yaml
+++ b/conf/config.yaml
@@ -142,6 +142,7 @@ plugins: # plugin list
- wolf-rbac
- proxy-cache
- tcp-logger
+ - proxy-mirror
stream_plugins:
- mqtt-proxy
diff --git a/doc/README.md b/doc/README.md
index cba2444..1854295 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -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
=======
diff --git a/doc/README_CN.md b/doc/README_CN.md
index 3fc9f9d..294727e 100644
--- a/doc/README_CN.md
+++ b/doc/README_CN.md
@@ -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):代理镜像插件提供镜像客户端请求的能力。
diff --git a/doc/plugins/proxy-mirror-cn.md b/doc/plugins/proxy-mirror-cn.md
new file mode 100644
index 0000000..4b3f073
--- /dev/null
+++ b/doc/plugins/proxy-mirror-cn.md
@@ -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
+ }
+ }
+}'
+```
+
+这时该插件已被禁用。
diff --git a/doc/plugins/proxy-mirror.md b/doc/plugins/proxy-mirror.md
new file mode 100644
index 0000000..3b6ee54
--- /dev/null
+++ b/doc/plugins/proxy-mirror.md
@@ -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.
diff --git a/lua/apisix/core/ctx.lua b/lua/apisix/core/ctx.lua
index 31d0d89..1e5082b 100644
--- a/lua/apisix/core/ctx.lua
+++ b/lua/apisix/core/ctx.lua
@@ -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,
diff --git a/lua/apisix/plugins/proxy-mirror.lua b/lua/apisix/plugins/proxy-mirror.lua
new file mode 100644
index 0000000..830f889
--- /dev/null
+++ b/lua/apisix/plugins/proxy-mirror.lua
@@ -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
diff --git a/t/APISIX.pm b/t/APISIX.pm
index 4dd710d..af7f2b0 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -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);
diff --git a/t/admin/plugins.t b/t/admin/plugins.t
index c5f34b7..b8771c7 100644
--- a/t/admin/plugins.t
+++ b/t/admin/plugins.t
@@ -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]
diff --git a/t/debug/debug-mode.t b/t/debug/debug-mode.t
index ead99df..d5a6c1d 100644
--- a/t/debug/debug-mode.t
+++ b/t/debug/debug-mode.t
@@ -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
diff --git a/t/plugin/proxy-mirror.t b/t/plugin/proxy-mirror.t
new file mode 100644
index 0000000..728b6a6
--- /dev/null
+++ b/t/plugin/proxy-mirror.t
@@ -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
+