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

[apisix] branch master updated: Add lables for Route/Service/Consumer/SSL (#2345)

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

liuxiran 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 9d0d351  Add lables for Route/Service/Consumer/SSL (#2345)
9d0d351 is described below

commit 9d0d351226de2b063cf963503b3c3fe44b76a066
Author: Joey <ma...@gmail.com>
AuthorDate: Fri Oct 9 14:05:14 2020 +0800

    Add lables for Route/Service/Consumer/SSL (#2345)
    
    Signed-off-by: imjoey <ma...@gmail.com>
---
 apisix/schema_def.lua  |  33 ++++++++++++
 doc/admin-api.md       |   5 ++
 doc/zh-cn/admin-api.md |   5 ++
 t/admin/consumers.t    |  75 ++++++++++++++++++++++++++
 t/admin/routes.t       | 141 +++++++++++++++++++++++++++++++++++++++++++++++++
 t/admin/services.t     | 138 +++++++++++++++++++++++++++++++++++++++++++++++
 t/admin/ssl.t          |  87 ++++++++++++++++++++++++++++++
 t/admin/upstream.t     |  10 ++--
 8 files changed, 489 insertions(+), 5 deletions(-)

diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua
index 2653069..0ce1fb6 100644
--- a/apisix/schema_def.lua
+++ b/apisix/schema_def.lua
@@ -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",
diff --git a/doc/admin-api.md b/doc/admin-api.md
index 29041c4..2e95ff7 100644
--- a/doc/admin-api.md
+++ b/doc/admin-api.md
@@ -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:
 
diff --git a/doc/zh-cn/admin-api.md b/doc/zh-cn/admin-api.md
index 3963142..8e958e7 100644
--- a/doc/zh-cn/admin-api.md
+++ b/doc/zh-cn/admin-api.md
@@ -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 配置内容:
 
diff --git a/t/admin/consumers.t b/t/admin/consumers.t
index 458e396..2dfdab3 100644
--- a/t/admin/consumers.t
+++ b/t/admin/consumers.t
@@ -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]
diff --git a/t/admin/routes.t b/t/admin/routes.t
index 20c42e1..1058005 100644
--- a/t/admin/routes.t
+++ b/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]
diff --git a/t/admin/services.t b/t/admin/services.t
index 5dcb8ad..00b0744 100644
--- a/t/admin/services.t
+++ b/t/admin/services.t
@@ -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]
diff --git a/t/admin/ssl.t b/t/admin/ssl.t
index 647c962..3cb7f18 100644
--- a/t/admin/ssl.t
+++ b/t/admin/ssl.t
@@ -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]
diff --git a/t/admin/upstream.t b/t/admin/upstream.t
index 92c1bb8..695c81a 100644
--- a/t/admin/upstream.t
+++ b/t/admin/upstream.t
@@ -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"]
                     }
                 }]]
                 )