mirror of
https://gitee.com/iresty/apisix.git
synced 2024-12-04 13:07:34 +08:00
Add lables for Route/Service/Consumer/SSL (#2345)
Signed-off-by: imjoey <majunjiev@gmail.com>
This commit is contained in:
parent
3d6c40deb5
commit
9d0d351226
@ -452,6 +452,15 @@ _M.route = {
|
||||
plugins = plugins_schema,
|
||||
upstream = upstream_schema,
|
||||
|
||||
labels = {
|
||||
description = "key/value pairs to specify attributes",
|
||||
type = "object",
|
||||
patternProperties = {
|
||||
[".*"] = label_value_def
|
||||
},
|
||||
maxProperties = 16
|
||||
},
|
||||
|
||||
service_id = id_schema,
|
||||
upstream_id = id_schema,
|
||||
service_protocol = {
|
||||
@ -490,6 +499,14 @@ _M.service = {
|
||||
name = {type = "string", maxLength = 50},
|
||||
desc = {type = "string", maxLength = 256},
|
||||
script = {type = "string", minLength = 10, maxLength = 102400},
|
||||
labels = {
|
||||
description = "key/value pairs to specify attributes",
|
||||
type = "object",
|
||||
patternProperties = {
|
||||
[".*"] = label_value_def
|
||||
},
|
||||
maxProperties = 16
|
||||
}
|
||||
},
|
||||
additionalProperties = false,
|
||||
}
|
||||
@ -504,6 +521,14 @@ _M.consumer = {
|
||||
pattern = [[^[a-zA-Z0-9_]+$]]
|
||||
},
|
||||
plugins = plugins_schema,
|
||||
labels = {
|
||||
description = "key/value pairs to specify attributes",
|
||||
type = "object",
|
||||
patternProperties = {
|
||||
[".*"] = label_value_def
|
||||
},
|
||||
maxProperties = 16
|
||||
},
|
||||
desc = {type = "string", maxLength = 256}
|
||||
},
|
||||
required = {"username"},
|
||||
@ -555,6 +580,14 @@ _M.ssl = {
|
||||
type = "integer",
|
||||
minimum = 1588262400, -- 2020/5/1 0:0:0
|
||||
},
|
||||
labels = {
|
||||
description = "key/value pairs to specify attributes",
|
||||
type = "object",
|
||||
patternProperties = {
|
||||
[".*"] = label_value_def
|
||||
},
|
||||
maxProperties = 16
|
||||
},
|
||||
status = {
|
||||
description = "ssl status, 1 to enable, 0 to disable",
|
||||
type = "integer",
|
||||
|
@ -70,6 +70,7 @@
|
||||
|upstream_id|False |Upstream|Enabled upstream id, see [Upstream](architecture-design.md#upstream) for more ||
|
||||
|service_id|False |Service|Binded Service configuration, see [Service](architecture-design.md#service) for more ||
|
||||
|service_protocol|False|Upstream protocol type|only `grpc` and `http` are supported|`http` is the default value; Must set `grpc` if using `gRPC proxy` or `gRPC transcode`|
|
||||
|labels |False |Match Rules|Key/value pairs to specify attributes|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
For the same type of parameters, such as `host` and `hosts`, `remote_addr` and `remote_addrs` cannot exist at the same time, only one of them can be selected. If enabled at the same time, the API will response an error.
|
||||
|
||||
@ -288,6 +289,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
|
||||
|upstream_id|False |Upstream|Enabled upstream id, see [Upstream](architecture-design.md#upstream) for more ||
|
||||
|name |False |Auxiliary |Identifies service names.|customer-xxxx|
|
||||
|desc |False |Auxiliary |service usage scenarios, and more.|customer xxxx|
|
||||
|labels |False |Match Rules|Key/value pairs to specify attributes|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
Config Example:
|
||||
|
||||
@ -426,6 +428,7 @@ Return response from etcd currently.
|
||||
|username|True|Name|Consumer name||
|
||||
|plugins |False |Plugin|See [Plugin](architecture-design.md#plugin) for more ||
|
||||
|desc |False |Auxiliary |Identifies route names, usage scenarios, and more.|customer xxxx|
|
||||
|labels |False |Match Rules|Key/value pairs to specify attributes|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
Config Example:
|
||||
|
||||
@ -507,6 +510,7 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst
|
||||
|desc |optional|upstream usage scenarios, and more.|
|
||||
|pass_host |optional|`pass` pass the client request host, `node` not pass the client request host, using the upstream node host, `rewrite` rewrite host by the configured `upstream_host`.|
|
||||
|upstream_host |optional|This option is only valid if the `pass_host` is `rewrite`.|
|
||||
|labels|False |Match Rules|Key/value pairs to specify attributes|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
|
||||
Config Example:
|
||||
@ -649,6 +653,7 @@ Return response from etcd currently.
|
||||
|cert|True|Public key|https Public key||
|
||||
|key|True|Private key|https Private key||
|
||||
|sni|True|Match Rules|https SNI||
|
||||
|labels|False |Match Rules|Key/value pairs to specify attributes|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
Config Example:
|
||||
|
||||
|
@ -74,6 +74,7 @@
|
||||
|priority |可选 |匹配规则|如果不同路由包含相同 `uri`,根据属性 `priority` 确定哪个 `route` 被优先匹配,值越大优先级越高,默认值为 0。|priority = 10|
|
||||
|vars |可选 |匹配规则|由一个或多个`{var, operator, val}`元素组成的列表,类似这样:`{{var, operator, val}, {var, operator, val}, ...}}`。例如:`{"arg_name", "==", "json"}`,表示当前请求参数 `name` 是 `json`。这里的 `var` 与 Nginx 内部自身变量命名是保持一致,所以也可以使用 `request_uri`、`host` 等;对于 `operator` 部分,目前已支持的运算符有 `==`、`~=`、`>`、`<` 和 `~~`。对于`>`和`<`两个运算符,会把结果先转换成 number 然后再做比较。查看支持的[运算符列表](#运算符列表)|{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}|
|
||||
|filter_func|可选|匹配规则|用户自定义的过滤函数。可以使用它来实现特殊场景的匹配要求实现。该函数默认接受一个名为 vars 的输入参数,可以用它来获取 Nginx 变量。|function(vars) return vars["arg_name"] == "json" end|
|
||||
|labels |可选 |匹配规则|标识附加属性的键值对|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
有两点需要特别注意:
|
||||
|
||||
@ -298,6 +299,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13
|
||||
|upstream_id| upstream 或 upstream_id 两个选一个 |Upstream|启用的 upstream id,详见 [Upstream](architecture-design.md#upstream)||
|
||||
|name |可选 |辅助 |标识服务名称。||
|
||||
|desc |可选 |辅助 |服务描述、使用场景等。||
|
||||
|labels |可选 |匹配规则|标识附加属性的键值对|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
serivce 对象 json 配置内容:
|
||||
|
||||
@ -439,6 +441,7 @@ HTTP/1.1 200 OK
|
||||
|username|必需|辅助|Consumer 名称。||
|
||||
|plugins|可选|Plugin|该 Consumer 对应的插件配置,它的优先级是最高的:Consumer > Route > Service。对于具体插件配置,可以参考 [Plugins](#plugin) 章节。||
|
||||
|desc |可选 |辅助|consumer描述||
|
||||
|labels |可选 |匹配规则|标识附加属性的键值对|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
consumer 对象 json 配置内容:
|
||||
|
||||
@ -521,6 +524,7 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上
|
||||
|desc |可选 |辅助|上游服务描述、使用场景等。||
|
||||
|pass_host |可选|枚举|`pass` 透传客户端请求的 host, `node` 不透传客户端请求的 host, 使用 upstream node 配置的 host, `rewrite` 使用 `upstream_host` 配置的值重写 host 。||
|
||||
|upstream_host |可选|辅助|只在 `pass_host` 配置为 `rewrite` 时有效。||
|
||||
|labels |可选 |匹配规则|标识附加属性的键值对|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
upstream 对象 json 配置内容:
|
||||
|
||||
@ -661,6 +665,7 @@ HTTP/1.1 200 OK
|
||||
|cert|必需|公钥|https 证书公钥||
|
||||
|key|必需|私钥|https 证书私钥||
|
||||
|sni|必需|匹配规则|https 证书SNI||
|
||||
|labels|可选|匹配规则|标识附加属性的键值对|{"version":"v2","build":"16","env":"production"}|
|
||||
|
||||
ssl 对象 json 配置内容:
|
||||
|
||||
|
@ -223,3 +223,78 @@ GET /t
|
||||
{"error_msg":"missing consumer name"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: add consumer with labels
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/consumers',
|
||||
ngx.HTTP_PUT,
|
||||
[[{
|
||||
"username":"jack",
|
||||
"desc": "new consumer",
|
||||
"labels": {
|
||||
"build":"16",
|
||||
"env":"production",
|
||||
"version":"v2"
|
||||
}
|
||||
}]],
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"username": "jack",
|
||||
"desc": "new consumer",
|
||||
"labels": {
|
||||
"build":"16",
|
||||
"env":"production",
|
||||
"version":"v2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"action": "set"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 8: invalid format of label value: set consumer
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/consumers',
|
||||
ngx.HTTP_PUT,
|
||||
[[{
|
||||
"username":"jack",
|
||||
"desc": "new consumer",
|
||||
"labels": {
|
||||
"env": ["production", "release"]
|
||||
}
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.print(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- error_code: 400
|
||||
--- response_body
|
||||
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
141
t/admin/routes.t
141
t/admin/routes.t
@ -2185,3 +2185,144 @@ GET /t
|
||||
--- error_code: 400
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 60: set route(with labels)
|
||||
--- 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,
|
||||
[[{
|
||||
"methods": ["GET"],
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"build": "16",
|
||||
"env": "production",
|
||||
"version": "v2"
|
||||
},
|
||||
|
||||
"uri": "/index.html"
|
||||
}]],
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"methods": [
|
||||
"GET"
|
||||
],
|
||||
"uri": "/index.html",
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"build": "16",
|
||||
"env": "production",
|
||||
"version": "v2"
|
||||
}
|
||||
},
|
||||
"key": "/apisix/routes/1"
|
||||
},
|
||||
"action": "set"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 61: patch route(change labels)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/routes/1',
|
||||
ngx.HTTP_PATCH,
|
||||
[[{
|
||||
"labels": {
|
||||
"build": "17"
|
||||
}
|
||||
}]],
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"methods": [
|
||||
"GET"
|
||||
],
|
||||
"uri": "/index.html",
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"env": "production",
|
||||
"version": "v2",
|
||||
"build": "17"
|
||||
}
|
||||
},
|
||||
"key": "/apisix/routes/1"
|
||||
},
|
||||
"action": "compareAndSwap"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 62: invalid format of label value: set route
|
||||
--- 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,
|
||||
[[{
|
||||
"methods": ["GET"],
|
||||
"uri": "/index.html",
|
||||
"labels": {
|
||||
"env": ["production", "release"]
|
||||
}
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.print(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- error_code: 400
|
||||
--- response_body
|
||||
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
@ -1179,3 +1179,141 @@ GET /t
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 33: set service(with labels)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/services/1',
|
||||
ngx.HTTP_PUT,
|
||||
[[{
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"build":"16",
|
||||
"env":"production",
|
||||
"version":"v2"
|
||||
},
|
||||
"desc": "new service"
|
||||
}]],
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"build": "16",
|
||||
"env": "production",
|
||||
"version": "v2"
|
||||
},
|
||||
"desc": "new service"
|
||||
},
|
||||
"key": "/apisix/services/1"
|
||||
},
|
||||
"action": "set"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 34: patch service(change labels)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/services/1',
|
||||
ngx.HTTP_PATCH,
|
||||
[[{
|
||||
"labels": {
|
||||
"build": "17"
|
||||
}
|
||||
}]],
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"build": "17",
|
||||
"env": "production",
|
||||
"version": "v2"
|
||||
},
|
||||
"desc": "new service"
|
||||
},
|
||||
"key": "/apisix/services/1"
|
||||
},
|
||||
"action": "compareAndSwap"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 35: invalid format of label value: set service
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local t = require("lib.test_admin").test
|
||||
local code, body = t('/apisix/admin/services/1',
|
||||
ngx.HTTP_PUT,
|
||||
[[{
|
||||
"upstream": {
|
||||
"nodes": {
|
||||
"127.0.0.1:8080": 1
|
||||
},
|
||||
"type": "roundrobin"
|
||||
},
|
||||
"labels": {
|
||||
"env": ["production", "release"]
|
||||
},
|
||||
"desc": "new service"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.print(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- error_code: 400
|
||||
--- response_body
|
||||
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
@ -530,3 +530,90 @@ GET /t
|
||||
{"error_msg":"invalid configuration: value should match only one schema, but matches none"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 15: set ssl(with labels)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local core = require("apisix.core")
|
||||
local t = require("lib.test_admin")
|
||||
|
||||
local ssl_cert = t.read_file("conf/cert/apisix.crt")
|
||||
local ssl_key = t.read_file("conf/cert/apisix.key")
|
||||
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com", labels = { version = "v2", build = "16", env = "production"}}
|
||||
|
||||
local code, body = t.test('/apisix/admin/ssl/1',
|
||||
ngx.HTTP_PUT,
|
||||
core.json.encode(data),
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"sni": "test.com",
|
||||
"labels": {
|
||||
"version": "v2",
|
||||
"build": "16",
|
||||
"env": "production"
|
||||
}
|
||||
},
|
||||
|
||||
"key": "/apisix/ssl/1"
|
||||
},
|
||||
"action": "set"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.say(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body
|
||||
passed
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 16: invalid format of label value: set ssl
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua_block {
|
||||
local core = require("apisix.core")
|
||||
local t = require("lib.test_admin")
|
||||
|
||||
local ssl_cert = t.read_file("conf/cert/apisix.crt")
|
||||
local ssl_key = t.read_file("conf/cert/apisix.key")
|
||||
local data = {cert = ssl_cert, key = ssl_key, sni = "test.com", labels = { env = {"production", "release"}}}
|
||||
|
||||
local code, body = t.test('/apisix/admin/ssl/1',
|
||||
ngx.HTTP_PUT,
|
||||
core.json.encode(data),
|
||||
[[{
|
||||
"node": {
|
||||
"value": {
|
||||
"sni": "test.com",
|
||||
"labels": {
|
||||
"env": ["production", "release"]
|
||||
}
|
||||
},
|
||||
|
||||
"key": "/apisix/ssl/1"
|
||||
},
|
||||
"action": "set"
|
||||
}]]
|
||||
)
|
||||
|
||||
ngx.status = code
|
||||
ngx.print(body)
|
||||
}
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- error_code: 400
|
||||
--- response_body
|
||||
{"error_msg":"invalid configuration: property \"labels\" validation failed: failed to validate env (matching \".*\"): wrong type: expected string, got table"}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
@ -1654,7 +1654,7 @@ GET /t
|
||||
"type": "roundrobin",
|
||||
"labels": {
|
||||
"build":"16",
|
||||
"env":"prodution",
|
||||
"env":"production",
|
||||
"version":"v2"
|
||||
}
|
||||
}]],
|
||||
@ -1667,7 +1667,7 @@ GET /t
|
||||
"type": "roundrobin",
|
||||
"labels": {
|
||||
"build":"16",
|
||||
"env":"prodution",
|
||||
"env":"production",
|
||||
"version":"v2"
|
||||
}
|
||||
},
|
||||
@ -1708,7 +1708,7 @@ passed
|
||||
"labels": {
|
||||
"version":"v2",
|
||||
"build":"16",
|
||||
"env":"prodution"
|
||||
"env":"production"
|
||||
}
|
||||
},
|
||||
"key": "/apisix/upstreams/1"
|
||||
@ -1752,7 +1752,7 @@ passed
|
||||
"labels": {
|
||||
"version":"v2",
|
||||
"build":"17",
|
||||
"env":"prodution"
|
||||
"env":"production"
|
||||
}
|
||||
},
|
||||
"key": "/apisix/upstreams/1"
|
||||
@ -1787,7 +1787,7 @@ passed
|
||||
},
|
||||
"type": "roundrobin",
|
||||
"labels": {
|
||||
"env": ["prodution", "release"]
|
||||
"env": ["production", "release"]
|
||||
}
|
||||
}]]
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user