You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/10/27 06:10:54 UTC

[apisix] branch master updated: feature: support percentage for fault injection (#2516)

This is an automated email from the ASF dual-hosted git repository.

membphis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 3306a3e  feature: support percentage for fault injection (#2516)
3306a3e is described below

commit 3306a3ed3ca58ad319a280e484b700fc20dc221b
Author: Alex Zhang <zc...@gmail.com>
AuthorDate: Tue Oct 27 14:10:44 2020 +0800

    feature: support percentage for fault injection (#2516)
---
 apisix/plugins/fault-injection.lua   |  27 +++++++--
 doc/plugins/fault-injection.md       |   2 +
 doc/zh-cn/plugins/fault-injection.md |   2 +
 t/plugin/fault-injection.t           | 112 +++++++++++++++++++++++++++++++++++
 4 files changed, 139 insertions(+), 4 deletions(-)

diff --git a/apisix/plugins/fault-injection.lua b/apisix/plugins/fault-injection.lua
index 8cf8b8d..aace3e2 100644
--- a/apisix/plugins/fault-injection.lua
+++ b/apisix/plugins/fault-injection.lua
@@ -14,8 +14,10 @@
 -- See the License for the specific language governing permissions and
 -- limitations under the License.
 --
-local core          = require("apisix.core")
-local sleep         = core.sleep
+local core = require("apisix.core")
+
+local sleep = core.sleep
+local random = math.random
 
 local plugin_name   = "fault-injection"
 
@@ -28,6 +30,7 @@ local schema = {
             properties = {
                 http_status = {type = "integer", minimum = 200},
                 body = {type = "string", minLength = 0},
+                percentage = {type = "integer", minimum = 0, maximum = 100}
             },
             minProperties = 1,
         },
@@ -35,6 +38,7 @@ local schema = {
             type = "object",
             properties = {
                 duration = {type = "number", minimum = 0},
+                percentage = {type = "integer", minimum = 0, maximum = 100}
             },
             minProperties = 1,
         }
@@ -51,6 +55,15 @@ local _M = {
 }
 
 
+local function sample_hit(percentage)
+    if not percentage then
+        return true
+    end
+
+    return random(0, 100) <= percentage
+end
+
+
 function _M.check_schema(conf)
     local ok, err = core.schema.check(schema, conf)
     if not ok then
@@ -64,11 +77,17 @@ end
 function _M.rewrite(conf, ctx)
     core.log.info("plugin rewrite phase, conf: ", core.json.delay_encode(conf))
 
-    if conf.delay and conf.delay.duration ~= nil then
+    if conf.delay
+       and conf.delay.duration ~= nil
+       and sample_hit(conf.delay.percentage)
+    then
         sleep(conf.delay.duration)
     end
 
-    if conf.abort and conf.abort.http_status ~= nil then
+    if conf.abort
+       and conf.abort.http_status ~= nil
+       and sample_hit(conf.abort.percentage)
+    then
         return conf.abort.http_status, conf.abort.body
     end
 end
diff --git a/doc/plugins/fault-injection.md b/doc/plugins/fault-injection.md
index 7209018..ff09cfc 100644
--- a/doc/plugins/fault-injection.md
+++ b/doc/plugins/fault-injection.md
@@ -29,7 +29,9 @@ Fault injection plugin, this plugin can be used with other plugins and will be e
 | ----------------- | ------- | ----------- | ------- | ---------- | ------------------------------------------------ |
 | abort.http_status | integer | optional    |         | [200, ...] | user-specified http code returned to the client. |
 | abort.body        | string  | optional    |         |            | response data returned to the client.            |
+| abort.percentage  | integer | optional    |         | [0, 100]   | percentage of requests to be aborted.            |
 | delay.duration    | number  | optional    |         |            | delay time (can be decimal).                     |
+| delay.percentage  | integer | optional    |         | [0, 100]   | percentage of requests to be delayed.            |
 
 Note: One of `abort` and `delay` must be specified.
 
diff --git a/doc/zh-cn/plugins/fault-injection.md b/doc/zh-cn/plugins/fault-injection.md
index eb50de8..ad40492 100644
--- a/doc/zh-cn/plugins/fault-injection.md
+++ b/doc/zh-cn/plugins/fault-injection.md
@@ -29,7 +29,9 @@
 | ----------------- | ------- | ------ | ------ | ---------- | -------------------------- |
 | abort.http_status | integer | 可选   |        | [200, ...] | 返回给客户端的 http 状态码 |
 | abort.body        | string  | 可选   |        |            | 返回给客户端的响应数据     |
+| abort.percentage  | integer | 可选   |        | [0, 100]   | 将被中断的请求占比         |
 | delay.duration    | number  | 可选   |        |            | 延迟时间,可以指定小数     |
+| delay.percentage  | integer | 可选   |        | [0, 100]   | 将被延迟的请求占比         |
 
 注:参数 abort 和 delay 至少要存在一个。
 
diff --git a/t/plugin/fault-injection.t b/t/plugin/fault-injection.t
index 9a44745..c427714 100644
--- a/t/plugin/fault-injection.t
+++ b/t/plugin/fault-injection.t
@@ -523,3 +523,115 @@ GET /hello HTTP/1.1
 Fault Injection!
 --- no_error_log
 [error]
+
+
+
+=== TEST 16: set route (abort injection but with zero percentage)
+--- 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": {
+                               "fault-injection": {
+                                   "abort": {
+                                      "http_status": 200,
+                                      "body": "Fault Injection!\n",
+                                      "percentage": 0
+                                   }
+                               },
+                               "redirect": {
+                                   "uri": "/hello/world",
+                                   "ret_code": 302
+                               }
+                           },
+                           "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 17: hit route (redirect)
+--- request
+GET /hello HTTP/1.1
+--- error_code: 302
+--- no_error_log
+[error]
+
+
+
+=== TEST 18: set route (delay injection but with zero percentage)
+--- 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": {
+                               "fault-injection": {
+                                   "delay": {
+                                       "duration": 1,
+                                       "percentage": 0
+                                   }
+                               },
+                               "proxy-rewrite": {
+                                   "uri": "/hello1"
+                               }
+                           },
+                           "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 19: hit route (no wait and return hello1 world)
+--- request
+GET /hello HTTP/1.1
+--- error_code: 200
+--- response_body
+hello1 world
+--- no_error_log
+[error]