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 b119a5c  bugfix: support more built-in parameters when set chash 
balancer (#775)
b119a5c is described below

commit b119a5c94b6ea59eb263f5f353944d3ebf00e81c
Author: Lien <lilien1...@users.noreply.github.com>
AuthorDate: Sun Nov 3 18:25:51 2019 +0800

    bugfix: support more built-in parameters when set chash balancer (#775)
---
 doc/architecture-design-cn.md |   2 +-
 doc/architecture-design.md    |   2 +-
 lua/apisix/schema_def.lua     |   3 +-
 t/admin/upstream.t            | 182 ++++++++++++++++++++++++++++++++++++++++++
 t/node/chash-balance.t        | 156 ++++++++++++++++++++++++++++++++++++
 5 files changed, 342 insertions(+), 3 deletions(-)

diff --git a/doc/architecture-design-cn.md b/doc/architecture-design-cn.md
index fcf4670..552bdd0 100644
--- a/doc/architecture-design-cn.md
+++ b/doc/architecture-design-cn.md
@@ -237,7 +237,7 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上
 |-------         |-----|------|
 |type            |必需|`roundrobin` 支持权重的负载,`chash` 一致性哈希,两者是二选一的|
 |nodes           |必需|哈希表,内部元素的 key 是上游机器地址列表,格式为`地址 + Port`,其中地址部分可以是 IP 
也可以是域名,比如 `192.168.1.100:80`、`foo.com:80`等。value 则是节点的权重,特别的,当权重值为 `0` 
有特殊含义,通常代表该上游节点失效,永远不希望被选中。|
-|key             |必需|该选项只有类型是 `chash` 才有效。根据 `key` 来查找对应的 node `id`,相同的 `key` 
在同一个对象中,永远返回相同 id|
+|key             |必需|该选项只有类型是 `chash` 才有效。根据 `key` 来查找对应的 node `id`,相同的 `key` 
在同一个对象中,永远返回相同 id,目前支持的 Nginx 内置变量有 `uri, server_name, server_addr, 
request_uri, remote_port, remote_addr, query_string, host, hostname, 
arg_***`,其中 `arg_***` 是来自URL的请求参数,[Nginx 
变量列表](http://nginx.org/en/docs/varindex.html)|
 |checks          |可选|配置健康检查的参数,详细可参考[health-check](health-check.md)|
 |retries         |可选|使用底层的 Nginx 重试机制将请求传递给下一个上游,默认不启用重试机制|
 
diff --git a/doc/architecture-design.md b/doc/architecture-design.md
index a4aaf6c..c225322 100644
--- a/doc/architecture-design.md
+++ b/doc/architecture-design.md
@@ -230,7 +230,7 @@ In addition to the basic complex equalization algorithm 
selection, APISIX's Upst
 |-------         |-----|------|
 |type            |required|`roundrobin` supports the weight of the load, 
`chash` consistency hash, pick one of them.|
 |nodes           |required|Hash table, the key of the internal element is the 
upstream machine address list, the format is `Address + Port`, where the 
address part can be IP or domain name, such as `192.168.1.100:80`, 
`foo.com:80`, etc. Value is the weight of the node. In particular, when the 
weight value is `0`, it has a special meaning, which usually means that the 
upstream node is invalid and never wants to be selected.|
-|key             |required|This option is only valid if the type is `chash`. 
Find the corresponding node `id` according to `key`, the same `key` in the same 
object, always return the same id.|
+|key             |required|This option is only valid if the type is `chash`. 
Find the corresponding node `id` according to `key`, the same `key` in the same 
object, always return the same id. For now, it support nginx built-in variables 
like `uri, server_name, server_addr, request_uri, remote_port, remote_addr, 
query_string, host, hostname, arg_***`, `arg_***` is arguments in the request 
line, [Nginx variables list](http://nginx.org/en/docs/varindex.html)|
 |checks          |optional|Configure the parameters of the health check. For 
details, refer to [health-check](health-check.md).|
 |retries         |optional|Pass the request to the next upstream using the 
underlying Nginx retry mechanism, the retry mechanism is not enabled by 
default.|
 
diff --git a/lua/apisix/schema_def.lua b/lua/apisix/schema_def.lua
index 6784ced..fc70770 100644
--- a/lua/apisix/schema_def.lua
+++ b/lua/apisix/schema_def.lua
@@ -252,7 +252,8 @@ local upstream_schema = {
         key = {
             description = "the key of chash for dynamic load balancing",
             type = "string",
-            enum = {"remote_addr"},
+            pattern = 
[[^((uri|server_name|server_addr|request_uri|remote_port]]
+                      .. 
[[|remote_addr|query_string|host|hostname)|arg_[0-9a-zA-z_-]+)$]],
         },
         desc = {type = "string", maxLength = 256},
         id = id_schema
diff --git a/t/admin/upstream.t b/t/admin/upstream.t
index b5bc94b..1453275 100644
--- a/t/admin/upstream.t
+++ b/t/admin/upstream.t
@@ -798,3 +798,185 @@ GET /t
 passed
 --- no_error_log
 [error]
+
+
+
+=== TEST 24: set upstream(type: chash)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "key": "server_name",
+                    "nodes": {
+                        "127.0.0.1:8080": 1
+                    },
+                    "type": "chash"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 25:  wrong upstream key
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "nodes": {
+                        "127.0.0.1:8080": 1,
+                        "127.0.0.1:8081": 2
+                    },
+                    "type": "chash",
+                    "key": "not_support",
+                    "desc": "new upstream"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.print(body)
+        }
+    }
+--- request
+GET /t
+--- error_code: 400
+--- response_body
+{"error_msg":"invalid configuration: property \"key\" validation failed: 
failed to match pattern 
\"^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname)|arg_[0-9a-zA-z_-]+)$\"
 with \"not_support\""}
+--- no_error_log
+[error]
+
+
+
+=== TEST 24: set upstream with args(type: chash)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "key": "arg_device_id",
+                    "nodes": {
+                        "127.0.0.1:8080": 1
+                    },
+                    "type": "chash",
+                    "desc": "new chash upstream"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 24: set upstream(type: chash)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "key": "server_name",
+                    "nodes": {
+                        "127.0.0.1:8080": 1
+                    },
+                    "type": "chash"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 25:  wrong upstream key
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "nodes": {
+                        "127.0.0.1:8080": 1,
+                        "127.0.0.1:8081": 2
+                    },
+                    "type": "chash",
+                    "key": "not_support",
+                    "desc": "new upstream"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.print(body)
+        }
+    }
+--- request
+GET /t
+--- error_code: 400
+--- response_body
+{"error_msg":"invalid configuration: property \"key\" validation failed: 
failed to match pattern 
\"^((uri|server_name|server_addr|request_uri|remote_port|remote_addr|query_string|host|hostname)|arg_[0-9a-zA-z_-]+)$\"
 with \"not_support\""}
+--- no_error_log
+[error]
+
+
+
+=== TEST 24: set upstream with args(type: chash)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/upstreams/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                    "key": "arg_device_id",
+                    "nodes": {
+                        "127.0.0.1:8080": 1
+                    },
+                    "type": "chash",
+                    "desc": "new chash upstream"
+                }]]
+                )
+
+            ngx.status = code
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
diff --git a/t/node/chash-balance.t b/t/node/chash-balance.t
index f012bbb..247fc37 100644
--- a/t/node/chash-balance.t
+++ b/t/node/chash-balance.t
@@ -265,3 +265,159 @@ GET /t
 [{"count":12,"port":"1980"}]
 --- no_error_log
 [error]
+
+
+
+=== TEST 7 set route(three upstream node with querystring)
+--- 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,
+                 [[{
+                    "uri": "/server_port",
+                    "upstream": {
+                        "key": "query_string",
+                        "type": "chash",
+                        "nodes": {
+                            "127.0.0.1:1980": 1,
+                            "127.0.0.1:1981": 1,
+                            "127.0.0.1:1982": 1
+                        }
+                    }
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 8: hit routes with querystring
+--- config
+    location /t {
+        content_by_lua_block {
+            local http = require "resty.http"
+            local uri = "http://127.0.0.1:"; .. ngx.var.server_port
+                        .. "/server_port?var=2&var2="
+
+            local ports_count = {}
+            for i = 1, 18 do
+                local httpc = http.new()
+                local res, err = httpc:request_uri(uri..i, {method = "GET"})
+                if not res then
+                    ngx.say(err)
+                    return
+                end
+                ports_count[res.body] = (ports_count[res.body] or 0) + 1
+            end 
+ 
+            local ports_arr = {}
+            for port, count in pairs(ports_count) do
+                table.insert(ports_arr, {port = port, count = count})
+            end
+
+            local function cmd(a, b)
+                return a.port > b.port
+            end
+            table.sort(ports_arr, cmd)
+
+            ngx.say(require("cjson").encode(ports_arr))
+            ngx.exit(200)
+        }
+    }
+--- request
+GET /t
+--- response_body
+[{"count":5,"port":"1982"},{"count":8,"port":"1981"},{"count":5,"port":"1980"}]
+--- no_error_log
+[error]
+
+
+
+=== TEST 9: set route(three upstream node with arg_xxx)
+--- 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,
+                 [[{
+                    "uri": "/server_port",
+                    "upstream": {
+                        "key": "arg_device_id",
+                        "type": "chash",
+                        "nodes": {
+                            "127.0.0.1:1980": 1,
+                            "127.0.0.1:1981": 1,
+                            "127.0.0.1:1982": 1
+                        }
+                    }
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 10: hit routes with args
+--- config
+    location /t {
+        content_by_lua_block {
+            local http = require "resty.http"
+            local uri = "http://127.0.0.1:"; .. ngx.var.server_port
+                        .. "/server_port?device_id="
+
+            local ports_count = {}
+            for i = 1, 18 do
+                local httpc = http.new()
+                local res, err = httpc:request_uri(uri..i, {method = "GET"})
+                if not res then
+                    ngx.say(err)
+                    return
+                end
+                ports_count[res.body] = (ports_count[res.body] or 0) + 1
+            end 
+ 
+            local ports_arr = {}
+            for port, count in pairs(ports_count) do
+                table.insert(ports_arr, {port = port, count = count})
+            end
+
+            local function cmd(a, b)
+                return a.port > b.port
+            end
+            table.sort(ports_arr, cmd)
+
+            ngx.say(require("cjson").encode(ports_arr))
+            ngx.exit(200)
+        }
+    }
+--- request
+GET /t
+--- response_body
+[{"count":5,"port":"1982"},{"count":7,"port":"1981"},{"count":6,"port":"1980"}]
+--- no_error_log
+[error]

Reply via email to