diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua index a2775109..2653069b 100644 --- a/apisix/schema_def.lua +++ b/apisix/schema_def.lua @@ -64,6 +64,16 @@ local remote_addr_def = { } +local label_value_def = { + description = "value of label", + type = "string", + pattern = [[^[a-zA-Z0-9-_.]+$]], + maxLength = 64, + minLength = 1 +} +_M.label_value_def = label_value_def + + local health_checker = { type = "object", properties = { @@ -332,6 +342,14 @@ local upstream_schema = { description = "enable websocket for request", type = "boolean" }, + labels = { + description = "key/value pairs to specify attributes", + type = "object", + patternProperties = { + [".*"] = label_value_def + }, + maxProperties = 16 + }, pass_host = { description = "mod of host passing", type = "string", diff --git a/doc/architecture-design.md b/doc/architecture-design.md index 068da16c..5b5078af 100644 --- a/doc/architecture-design.md +++ b/doc/architecture-design.md @@ -265,6 +265,7 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst |enable_websocket|optional| enable `websocket`(boolean), default `false`.| |timeout|optional| Set the timeout for connection, sending and receiving messages. | |desc |optional|Identifies route names, usage scenarios, and more.| +|labels |optional|The key/value pairs to specify attributes. | |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`.| diff --git a/doc/zh-cn/architecture-design.md b/doc/zh-cn/architecture-design.md index c56a2261..f2f07871 100644 --- a/doc/zh-cn/architecture-design.md +++ b/doc/zh-cn/architecture-design.md @@ -273,6 +273,7 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上 |checks |可选|配置健康检查的参数,详细可参考[health-check](../health-check.md)| |retries |可选|使用底层的 Nginx 重试机制将请求传递给下一个上游,默认 APISIX 会启用重试机制,根据配置的后端节点个数设置重试次数,如果此参数显式被设置将会覆盖系统默认设置的重试次数。| |enable_websocket|可选| 是否启用 `websocket`(布尔值),默认不启用| +|labels |可选| 用于标识属性的键值对。 | |pass_host |可选|`pass` 透传客户端请求的 host, `node` 不透传客户端请求的 host, 使用 upstream node 配置的 host, `rewrite` 使用 `upstream_host` 配置的值重写 host 。| |upstream_host |可选|只在 `pass_host` 配置为 `rewrite` 时有效。| diff --git a/t/admin/upstream.t b/t/admin/upstream.t index 3bd5be83..92c1bb80 100644 --- a/t/admin/upstream.t +++ b/t/admin/upstream.t @@ -1637,3 +1637,169 @@ GET /t --- error_code: 400 --- no_error_log [error] + + + +=== TEST 50: set upstream(with labels) +--- 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 + }, + "type": "roundrobin", + "labels": { + "build":"16", + "env":"prodution", + "version":"v2" + } + }]], + [[{ + "node": { + "value": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin", + "labels": { + "build":"16", + "env":"prodution", + "version":"v2" + } + }, + "key": "/apisix/upstreams/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 51: get upstream(with labels) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_GET, + nil, + [[{ + "node": { + "value": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin", + "labels": { + "version":"v2", + "build":"16", + "env":"prodution" + } + }, + "key": "/apisix/upstreams/1" + }, + "action": "get" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 52: patch upstream(only labels) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PATCH, + [[{ + "labels": { + "build": "17" + } + }]], + [[{ + "node": { + "value": { + "nodes": { + "127.0.0.1:8080": 1 + }, + "type": "roundrobin", + "labels": { + "version":"v2", + "build":"17", + "env":"prodution" + } + }, + "key": "/apisix/upstreams/1" + }, + "action": "compareAndSwap" + }]] + ) + + ngx.status = code + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 53: invalid format of label value: set upstream +--- 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 + }, + "type": "roundrobin", + "labels": { + "env": ["prodution", "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]