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

chenjunxu 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 a53b470  feat: support saving k8s deployment info to upstream (#1502)
a53b470 is described below

commit a53b4707fb03efa40966a00f1525bdedad2334ce
Author: nic-chen <[email protected]>
AuthorDate: Mon Apr 27 10:47:17 2020 +0800

    feat: support saving k8s deployment info to upstream (#1502)
    
    * feat: support save k8s deployment info to upstream
---
 apisix/admin/upstreams.lua    | 12 ++++---
 apisix/schema_def.lua         | 28 ++++++++++++++--
 doc/admin-api-cn.md           | 10 +++++-
 doc/admin-api.md              | 10 +++++-
 doc/architecture-design-cn.md | 13 +++++---
 doc/architecture-design.md    | 13 +++++---
 t/admin/routes.t              |  4 +--
 t/admin/services.t            |  6 ++--
 t/admin/upstream.t            |  4 +--
 t/node/upstream.t             | 76 +++++++++++++++++++++++++++++++++++++++----
 10 files changed, 142 insertions(+), 34 deletions(-)

diff --git a/apisix/admin/upstreams.lua b/apisix/admin/upstreams.lua
index b49c33a..e989cd5 100644
--- a/apisix/admin/upstreams.lua
+++ b/apisix/admin/upstreams.lua
@@ -19,7 +19,6 @@ local get_routes = require("apisix.router").http_routes
 local get_services = require("apisix.http.service").services
 local tostring = tostring
 local ipairs = ipairs
-local tonumber = tonumber
 local type = type
 
 
@@ -99,17 +98,20 @@ local function check_conf(id, conf, need_id)
     if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
         return nil, {error_msg = "wrong upstream id"}
     end
+
+    -- let schema check id
+    if id and not conf.id then
+        conf.id = id
+    end
+
     core.log.info("schema: ", core.json.delay_encode(core.schema.upstream))
     core.log.info("conf  : ", core.json.delay_encode(conf))
+
     local ok, err = check_upstream_conf(conf)
     if not ok then
         return nil, {error_msg = err}
     end
 
-    if need_id and not tonumber(id) then
-        return nil, {error_msg = "wrong type of service id"}
-    end
-
     return need_id and id or true
 end
 
diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua
index 50a783a..e261c98 100644
--- a/apisix/schema_def.lua
+++ b/apisix/schema_def.lua
@@ -29,8 +29,8 @@ local plugins_schema = {
 local id_schema = {
     anyOf = {
         {
-            type = "string", minLength = 1, maxLength = 32,
-            pattern = [[^[0-9]+$]]
+            type = "string", minLength = 1, maxLength = 64,
+            pattern = [[^[a-zA-Z0-9-_]+$]]
         },
         {type = "integer", minimum = 1}
     }
@@ -253,6 +253,25 @@ local upstream_schema = {
             },
             required = {"connect", "send", "read"},
         },
+        k8s_deployment_info = {
+            type = "object",
+            properties = {
+                namespace = {type = "string", description = "k8s namespace"},
+                deploy_name = {type = "string", description = "k8s deployment 
name"},
+                service_name = {type = "string", description = "k8s service 
name"},
+                port = {type = "number", minimum = 0},
+                backend_type = {
+                    type = "string",
+                    default = "pod",
+                    description = "k8s service name",
+                    enum = {"svc", "pod"}
+                },
+            },
+            anyOf = {
+                {required = {"namespace", "deploy_name", "port"}},
+                {required = {"namespace", "service_name", "port"}},
+            },
+        },
         type = {
             description = "algorithms of load balancing",
             type = "string",
@@ -280,7 +299,10 @@ local upstream_schema = {
         desc = {type = "string", maxLength = 256},
         id = id_schema
     },
-    required = {"nodes", "type"},
+    anyOf = {
+        {required = {"type", "nodes"}},
+        {required = {"type", "k8s_deployment_info"}},
+    },
     additionalProperties = false,
 }
 
diff --git a/doc/admin-api-cn.md b/doc/admin-api-cn.md
index d61bbe9..7a7d355 100644
--- a/doc/admin-api-cn.md
+++ b/doc/admin-api-cn.md
@@ -344,7 +344,8 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上
 
 |名字      |可选项   |类型 |说明        |示例|
 |---------|---------|----|-----------|----|
-|nodes           |必需|Node|哈希表,内部元素的 key 是上游机器地址列表,格式为`地址 + Port`,其中地址部分可以是 IP 
也可以是域名,比如 `192.168.1.100:80`、`foo.com:80`等。value 则是节点的权重,特别的,当权重值为 `0` 
有特殊含义,通常代表该上游节点失效,永远不希望被选中。|`192.168.1.100:80`|
+|nodes           |与 `k8s_deployment_info` 二选一|Node|哈希表,内部元素的 key 
是上游机器地址列表,格式为`地址 + Port`,其中地址部分可以是 IP 也可以是域名,比如 
`192.168.1.100:80`、`foo.com:80`等。value 则是节点的权重,特别的,当权重值为 `0` 
有特殊含义,通常代表该上游节点失效,永远不希望被选中。|`192.168.1.100:80`|
+|k8s_deployment_info|与 `nodes` 二选一|哈希表|字段包括 
`namespace`、`deploy_name`、`service_name`、`port`、`backend_type`,其中 `port` 
字段为数值,`backend_type` 为 `pod` 或 `service`,其他为字符串 | `{"namespace": 
"test-namespace", "deploy_name": "test-deploy-name", "service_name": 
"test-service-name", "backend_type": "pod", "port": 8080}` |
 |type            |必需|枚举|`roundrobin` 支持权重的负载,`chash` 
一致性哈希,两者是二选一的|`roundrobin`||
 |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_checker|配置健康检查的参数,详细可参考[health-check](health-check.md)||
@@ -367,6 +368,13 @@ upstream 对象 json 配置内容:
     },
     "enable_websocket": true,
     "nodes": {"host:80": 100},  # 上游机器地址列表,格式为`地址 + Port`
+    "k8s_deployment_info": {    # k8s deployment 信息
+        "namespace": "test-namespace",
+        "deploy_name": "test-deploy-name",
+        "service_name": "test-service-name",
+        "backend_type": "pod",   # pod or service
+        "port": 8080
+    },
     "type":"roundrobin",        # chash or roundrobin
     "checks": {},               # 配置健康检查的参数
     "hash_on": "",
diff --git a/doc/admin-api.md b/doc/admin-api.md
index 9c40948..f60ccb6 100644
--- a/doc/admin-api.md
+++ b/doc/admin-api.md
@@ -337,7 +337,8 @@ In addition to the basic complex equalization algorithm 
selection, APISIX's Upst
 |Name    |Optional|Description|
 |-------         |-----|------|
 |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.|
+|nodes           |required if `k8s_deployment_info` not configured|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.|
+|k8s_deployment_info|required if `nodes` not configured|fields: 
`namespace`、`deploy_name`、`service_name`、`port`、`backend_type`, `port` is 
number, `backend_type` is `pod` or `service`, others is string. |
 |hash_on         |optional|This option is only valid if the `type` is `chash`. 
Supported types `vars`(Nginx variables), `header`(custom header), `cookie`, 
`consumer`, the default value is `vars`.|
 |key             |required|This option is only valid if the `type` is `chash`. 
Find the corresponding node `id` according to `hash_on` and `key`. When 
`hash_on` is set as `vars`, `key` is the required parameter, 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). When `hash_ [...]
 |checks          |optional|Configure the parameters of the health check. For 
details, refer to [health-check](health-check.md).|
@@ -359,6 +360,13 @@ Config Example:
     },
     "enable_websocket": true,
     "nodes": {"host:80": 100},  # Upstream machine address list, the format is 
`Address + Port`
+    "k8s_deployment_info": {    # kubernetes deployment info
+        "namespace": "test-namespace",
+        "deploy_name": "test-deploy-name",
+        "service_name": "test-service-name",
+        "backend_type": "pod",    # pod or service
+        "port": 8080
+    },
     "type":"roundrobin",        # chash or roundrobin
     "checks": {},               # Health check parameters
     "hash_on": "",
diff --git a/doc/architecture-design-cn.md b/doc/architecture-design-cn.md
index 251a0f3..3fa6884 100644
--- a/doc/architecture-design-cn.md
+++ b/doc/architecture-design-cn.md
@@ -238,7 +238,8 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上
 |名字    |可选|说明|
 |-------         |-----|------|
 |type            |必填|`roundrobin` 支持权重的负载,`chash` 一致性哈希,两者是二选一的|
-|nodes           |必填|哈希表,内部元素的 key 是上游机器地址列表,格式为`地址 + Port`,其中地址部分可以是 IP 
也可以是域名,比如 `192.168.1.100:80`、`foo.com:80` 等。value 则是节点的权重。当权重值为 `0` 
代表该上游节点失效,不会被选中,可以用于暂时摘除节点的情况。|
+|nodes           |与 `k8s_deployment_info` 二选一|哈希表,内部元素的 key 是上游机器地址列表,格式为`地址 + 
Port`,其中地址部分可以是 IP 也可以是域名,比如 `192.168.1.100:80`、`foo.com:80` 等。value 
则是节点的权重。当权重值为 `0` 代表该上游节点失效,不会被选中,可以用于暂时摘除节点的情况。|
+|k8s_deployment_info|与 `nodes` 二选一|哈希表|字段包括 
`namespace`、`deploy_name`、`service_name`、`port`、`backend_type`,其中 `port` 
字段为数值,`backend_type` 为 `pod` 或 `service`,其他为字符串 |
 |key             |可选|在 `type` 等于 `chash` 是必选项。 `key` 需要配合 `hash_on` 来使用,通过 
`hash_on` 和 `key` 来查找对应的 node `id`|
 |hash_on         |可选|`hash_on` 支持的类型有 
`vars`(Nginx内置变量),`header`(自定义header),`cookie`,`consumer`,默认值为 `vars`|
 |checks          |可选|配置健康检查的参数,详细可参考[health-check](health-check.md)|
@@ -259,10 +260,12 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上
 curl http://127.0.0.1:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: 
edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
 {
     "type": "roundrobin",
-    "nodes": {
-        "127.0.0.1:80": 1,
-        "127.0.0.2:80": 2,
-        "foo.com:80": 3
+    "k8s_deployment_info": {
+        "namespace": "test-namespace",
+        "deploy_name": "test-deploy-name",
+        "service_name": "test-service-name",
+        "backend_type": "pod",
+        "port": 8080
     }
 }'
 
diff --git a/doc/architecture-design.md b/doc/architecture-design.md
index e580ab3..9edaadb 100644
--- a/doc/architecture-design.md
+++ b/doc/architecture-design.md
@@ -233,7 +233,8 @@ In addition to the basic complex equalization algorithm 
selection, APISIX's Upst
 |Name    |Optional|Description|
 |-------         |-----|------|
 |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.|
+|nodes           |required if `k8s_deployment_info` not configured|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.|
+|k8s_deployment_info |required if `nodes` not configured|fields: 
`namespace`、`deploy_name`、`service_name`、`port`、`backend_type`, `port` is 
number, `backend_type` is `pod` or `service`, others is string. |
 |hash_on         |optional|This option is only valid if the `type` is `chash`. 
Supported types `vars`(Nginx variables), `header`(custom header), `cookie`, 
`consumer`, the default value is `vars`.|
 |key             |required|This option is only valid if the `type` is `chash`. 
Find the corresponding node `id` according to `hash_on` and `key`. When 
`hash_on` is set as `vars`, `key` is the required parameter, 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). When `hash_ [...]
 |checks          |optional|Configure the parameters of the health check. For 
details, refer to [health-check](health-check.md).|
@@ -248,10 +249,12 @@ Create an upstream object use case:
 curl http://127.0.0.1:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: 
edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
 {
     "type": "roundrobin",
-    "nodes": {
-        "127.0.0.1:80": 1,
-        "127.0.0.2:80": 2,
-        "foo.com:80": 3
+    "k8s_deployment_info": {
+        "namespace": "test-namespace",
+        "deploy_name": "test-deploy-name",
+        "service_name": "test-service-name",
+        "backend_type": "pod",
+        "port": 8080
     }
 }'
 
diff --git a/t/admin/routes.t b/t/admin/routes.t
index 4c54c4f..78ab5c6 100644
--- a/t/admin/routes.t
+++ b/t/admin/routes.t
@@ -434,7 +434,7 @@ GET /t
             local code, body = t('/apisix/admin/routes/1',
                  ngx.HTTP_PUT,
                  [[{
-                        "service_id": "invalid_id",
+                        "service_id": "invalid_id$",
                         "uri": "/index.html"
                 }]]
                 )
@@ -569,7 +569,7 @@ GET /t
             local code, body = t('/apisix/admin/routes/1',
                  ngx.HTTP_PUT,
                  [[{
-                    "upstream_id": "invalid",
+                    "upstream_id": "invalid$",
                     "uri": "/index.html"
                 }]]
                 )
diff --git a/t/admin/services.t b/t/admin/services.t
index 97d0aea..6c6f503 100644
--- a/t/admin/services.t
+++ b/t/admin/services.t
@@ -353,7 +353,7 @@ GET /t
     location /t {
         content_by_lua_block {
             local t = require("lib.test_admin").test
-            local code, body = t('/apisix/admin/services/invalid_id',
+            local code, body = t('/apisix/admin/services/invalid_id$',
                  ngx.HTTP_PUT,
                  [[{
                     "plugins": {
@@ -475,7 +475,7 @@ GET /t
             local code, body = t('/apisix/admin/services',
                  ngx.HTTP_PUT,
                  [[{
-                    "id": "invalid_id",
+                    "id": "invalid_id$",
                     "plugins": {}
                 }]]
                 )
@@ -530,7 +530,7 @@ GET /t
                  ngx.HTTP_PUT,
                  [[{
                     "id": 1,
-                    "upstream_id": "invalid"
+                    "upstream_id": "invalid$"
                 }]]
                 )
 
diff --git a/t/admin/upstream.t b/t/admin/upstream.t
index 6735914..da13134 100644
--- a/t/admin/upstream.t
+++ b/t/admin/upstream.t
@@ -244,7 +244,7 @@ GET /t
     location /t {
         content_by_lua_block {
             local t = require("lib.test_admin").test
-            local code, body = t('/apisix/admin/upstreams/invalid_id',
+            local code, body = t('/apisix/admin/upstreams/invalid_id$',
                  ngx.HTTP_PUT,
                  [[{
                     "nodes": {
@@ -374,7 +374,7 @@ GET /t
             local code, body = t('/apisix/admin/upstreams',
                  ngx.HTTP_PUT,
                  [[{
-                    "id": "invalid_id",
+                    "id": "invalid_id$",
                     "nodes": {
                         "127.0.0.1:8080": 1
                     },
diff --git a/t/node/upstream.t b/t/node/upstream.t
index bfdbba9..c6ae077 100644
--- a/t/node/upstream.t
+++ b/t/node/upstream.t
@@ -26,7 +26,69 @@ run_tests();
 
 __DATA__
 
-=== TEST 1: set upstream(id: 1)
+=== TEST 1: set upstream(id: 1) invalid parameters
+--- 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,
+                 [[{
+                    "type": "roundrobin",
+                    "desc": "new upstream"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- error_code: 400
+--- no_error_log
+[error]
+
+
+
+=== TEST 2: set upstream(id: 1) k8s deployment info
+--- 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,
+                 [[{
+                    "k8s_deployment_info": {
+                        "namespace": "test-namespace",
+                        "deploy_name": "test-deploy-name",
+                        "service_name": "test-service-name",
+                        "backend_type": "pod",
+                        "port": 8080
+                    },
+                    "type": "roundrobin",
+                    "desc": "new upstream"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 3: set upstream(id: 1) nodes
 --- config
     location /t {
         content_by_lua_block {
@@ -57,7 +119,7 @@ passed
 
 
 
-=== TEST 2: set route(id: 1)
+=== TEST 4: set route(id: 1)
 --- config
     location /t {
         content_by_lua_block {
@@ -85,7 +147,7 @@ passed
 
 
 
-=== TEST 3: /not_found
+=== TEST 5: /not_found
 --- request
 GET /not_found
 --- error_code: 404
@@ -106,7 +168,7 @@ hello world
 
 
 
-=== TEST 5: delete upstream(id: 1)
+=== TEST 6: delete upstream(id: 1)
 --- config
     location /t {
         content_by_lua_block {
@@ -131,7 +193,7 @@ GET /t
 
 
 
-=== TEST 6: delete route(id: 1)
+=== TEST 7: delete route(id: 1)
 --- config
     location /t {
         content_by_lua_block {
@@ -155,7 +217,7 @@ GET /t
 
 
 
-=== TEST 7: delete upstream(id: 1)
+=== TEST 8: delete upstream(id: 1)
 --- config
     location /t {
         content_by_lua_block {
@@ -179,7 +241,7 @@ GET /t
 
 
 
-=== TEST 8: delete upstream again(id: 1)
+=== TEST 9: delete upstream again(id: 1)
 --- config
     location /t {
         content_by_lua_block {

Reply via email to