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

majunjie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new fc89bc4  feat: basic support Apache APISIX 2.9 (#2117)
fc89bc4 is described below

commit fc89bc4b3f70576cb630525985e80fc70068f81f
Author: bzp2010 <bzp2...@apache.org>
AuthorDate: Fri Sep 3 22:36:24 2021 +0800

    feat: basic support Apache APISIX 2.9 (#2117)
    
    * feat: update json schema file
    
    * feat: update entity definition
    
    * feat: add new upstream property to frontend
    
    * fix: ci test 1
    
    * fix: unit test
    
    * fix: cli test
    
    * fix: lint
    
    * feat: add upstream backend e2e test
    
    * feat: add upstream frontend e2e test
    
    * fix: backend e2e test
    
    * fix: limit-conn plugin form and e2e test
    
    * fix: fe ci error
    
    * fix: review
    
    * fix: etcd 3.4.13
    
    * fix: run test with apisix2.9
    
    * fix: ci
    
    * fix: ci
    
    * fix: ci
    
    Co-authored-by: liuxiran <belovedx...@126.com>
---
 .github/workflows/backend-cli-test.yml             |   2 +-
 .github/workflows/go-lint.yml                      |  22 -
 api/conf/schema.json                               | 516 ++++++++++++++++-----
 api/internal/core/entity/entity.go                 |  69 +--
 api/internal/core/store/validate_test.go           |  21 +-
 api/internal/handler/schema/plugin_test.go         |   2 +-
 api/internal/handler/upstream/upstream_test.go     | 168 +++----
 api/test/docker/docker-compose.yaml                |   2 +-
 api/test/e2e/json_schema_validate_test.go          |  61 ---
 api/test/e2e/route_import_test.go                  |   4 +-
 api/test/e2enew/schema/schema_test.go              |   2 +-
 .../e2enew/upstream/upstream_keepalive_pool.go     |  66 +++
 api/test/e2enew/upstream/upstream_retry.go         |  63 +++
 api/test/e2enew/upstream/upstream_test.go          |   1 -
 web/cypress/fixtures/export-route-dataset.json     |  33 +-
 web/cypress/fixtures/plugin-dataset.json           |  24 +-
 .../consumer/create-with-limit-conn-form.spec.js   |   2 +
 .../upstream/create_and_delete_upstream.spec.js    |  61 +++
 web/src/components/Plugin/UI/limit-conn.tsx        |  29 +-
 web/src/components/Plugin/locales/en-US.ts         |   2 +
 web/src/components/Plugin/locales/zh-CN.ts         |   3 +
 web/src/components/Upstream/UpstreamForm.tsx       |  13 +
 .../Upstream/components/KeepalivePool.tsx          |  89 ++++
 .../Upstream/components/RetryTimeout.tsx           |  41 ++
 web/src/components/Upstream/locales/en-US.ts       |  14 +
 web/src/components/Upstream/locales/zh-CN.ts       |  13 +
 web/src/pages/Upstream/locales/en-US.ts            |   1 +
 web/src/pages/Upstream/locales/zh-CN.ts            |   1 +
 web/src/pages/Upstream/typing.d.ts                 |   8 +
 29 files changed, 967 insertions(+), 366 deletions(-)

diff --git a/.github/workflows/backend-cli-test.yml 
b/.github/workflows/backend-cli-test.yml
index 55b42bb..23234d7 100644
--- a/.github/workflows/backend-cli-test.yml
+++ b/.github/workflows/backend-cli-test.yml
@@ -17,7 +17,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        etcd: [3.4.13]
+        etcd: [3.4.14]
     services:
       etcd:
         image: bitnami/etcd:${{ matrix.etcd }}
diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml
index 7f495aa..635e22d 100644
--- a/.github/workflows/go-lint.yml
+++ b/.github/workflows/go-lint.yml
@@ -12,25 +12,6 @@ on:
       - 'api/**'
 
 jobs:
-  go-filter:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-        with:
-          submodule: true
-
-      - uses: ./.github/actions/paths-filter
-        id: changes
-        with:
-          filters: |
-            go:
-              - '**.go'
-          working-directory: 'api'
-          list-files: shell
-    outputs:
-      matches: ${{ steps.changes.outputs.go }}
-      files: ${{ steps.changes.outputs.go_files }}
-
   golangci:
     runs-on: ubuntu-latest
     needs: go-filter
@@ -45,11 +26,8 @@ jobs:
           working-directory: api
           args: --tests=false
           only-new-issues: true
-
   gofmt:
     runs-on: ubuntu-latest
-    needs: go-filter
-    if: needs.go-filter.outputs.matches == 'true'
     steps:
       - uses: actions/checkout@v2
       - name: setup go
diff --git a/api/conf/schema.json b/api/conf/schema.json
index 9b454b5..2fbbeed 100644
--- a/api/conf/schema.json
+++ b/api/conf/schema.json
@@ -1,7 +1,6 @@
 {
        "main": {
                "consumer": {
-                       "additionalProperties": false,
                        "properties": {
                                "create_time": {
                                        "type": "integer"
@@ -41,7 +40,6 @@
                        "type": "object"
                },
                "global_rule": {
-                       "additionalProperties": false,
                        "properties": {
                                "create_time": {
                                        "type": "integer"
@@ -68,7 +66,6 @@
                        "type": "object"
                },
                "plugin_config": {
-                       "additionalProperties": false,
                        "properties": {
                                "create_time": {
                                        "type": "integer"
@@ -115,7 +112,6 @@
                "plugins": {
                        "items": {
                                "properties": {
-                                       "additionalProperties": false,
                                        "name": {
                                                "minLength": 1,
                                                "type": "string"
@@ -130,7 +126,6 @@
                        "type": "array"
                },
                "proto": {
-                       "additionalProperties": false,
                        "properties": {
                                "content": {
                                        "maxLength": 1048576,
@@ -163,7 +158,6 @@
                        "type": "object"
                },
                "route": {
-                       "additionalProperties": false,
                        "allOf": [{
                                "oneOf": [{
                                        "required": ["uri"]
@@ -419,7 +413,6 @@
                                        "type": "integer"
                                },
                                "upstream": {
-                                       "additionalProperties": false,
                                        "oneOf": [{
                                                "required": ["nodes", "type"]
                                        }, {
@@ -427,7 +420,6 @@
                                        }],
                                        "properties": {
                                                "checks": {
-                                                       "additionalProperties": 
false,
                                                        "anyOf": [{
                                                                "required": 
["active"]
                                                        }, {
@@ -652,6 +644,26 @@
                                                                "type": 
"integer"
                                                        }]
                                                },
+                                               "keepalive_pool": {
+                                                       "properties": {
+                                                               "idle_timeout": 
{
+                                                                       
"default": 60,
+                                                                       
"minimum": 0,
+                                                                       "type": 
"number"
+                                                               },
+                                                               "requests": {
+                                                                       
"default": 1000,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               },
+                                                               "size": {
+                                                                       
"default": 320,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               }
+                                                       },
+                                                       "type": "object"
+                                               },
                                                "key": {
                                                        "description": "the key 
of chash for dynamic load balancing",
                                                        "type": "string"
@@ -728,6 +740,10 @@
                                                        "minimum": 0,
                                                        "type": "integer"
                                                },
+                                               "retry_timeout": {
+                                                       "minimum": 0,
+                                                       "type": "number"
+                                               },
                                                "scheme": {
                                                        "default": "http",
                                                        "enum": ["grpc", 
"grpcs", "http", "https"]
@@ -773,7 +789,6 @@
                                                },
                                                "type": {
                                                        "description": 
"algorithms of load balancing",
-                                                       "enum": ["chash", 
"ewma", "least_conn", "roundrobin"],
                                                        "type": "string"
                                                },
                                                "update_time": {
@@ -818,7 +833,6 @@
                        "type": "object"
                },
                "service": {
-                       "additionalProperties": false,
                        "properties": {
                                "create_time": {
                                        "type": "integer"
@@ -873,7 +887,6 @@
                                        "type": "integer"
                                },
                                "upstream": {
-                                       "additionalProperties": false,
                                        "oneOf": [{
                                                "required": ["nodes", "type"]
                                        }, {
@@ -881,7 +894,6 @@
                                        }],
                                        "properties": {
                                                "checks": {
-                                                       "additionalProperties": 
false,
                                                        "anyOf": [{
                                                                "required": 
["active"]
                                                        }, {
@@ -1106,6 +1118,26 @@
                                                                "type": 
"integer"
                                                        }]
                                                },
+                                               "keepalive_pool": {
+                                                       "properties": {
+                                                               "idle_timeout": 
{
+                                                                       
"default": 60,
+                                                                       
"minimum": 0,
+                                                                       "type": 
"number"
+                                                               },
+                                                               "requests": {
+                                                                       
"default": 1000,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               },
+                                                               "size": {
+                                                                       
"default": 320,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               }
+                                                       },
+                                                       "type": "object"
+                                               },
                                                "key": {
                                                        "description": "the key 
of chash for dynamic load balancing",
                                                        "type": "string"
@@ -1182,6 +1214,10 @@
                                                        "minimum": 0,
                                                        "type": "integer"
                                                },
+                                               "retry_timeout": {
+                                                       "minimum": 0,
+                                                       "type": "number"
+                                               },
                                                "scheme": {
                                                        "default": "http",
                                                        "enum": ["grpc", 
"grpcs", "http", "https"]
@@ -1227,7 +1263,6 @@
                                                },
                                                "type": {
                                                        "description": 
"algorithms of load balancing",
-                                                       "enum": ["chash", 
"ewma", "least_conn", "roundrobin"],
                                                        "type": "string"
                                                },
                                                "update_time": {
@@ -1255,7 +1290,6 @@
                        "type": "object"
                },
                "ssl": {
-                       "additionalProperties": false,
                        "oneOf": [{
                                "required": ["cert", "key", "sni"]
                        }, {
@@ -1444,7 +1478,6 @@
                                        "type": "integer"
                                },
                                "upstream": {
-                                       "additionalProperties": false,
                                        "oneOf": [{
                                                "required": ["nodes", "type"]
                                        }, {
@@ -1452,7 +1485,6 @@
                                        }],
                                        "properties": {
                                                "checks": {
-                                                       "additionalProperties": 
false,
                                                        "anyOf": [{
                                                                "required": 
["active"]
                                                        }, {
@@ -1677,6 +1709,26 @@
                                                                "type": 
"integer"
                                                        }]
                                                },
+                                               "keepalive_pool": {
+                                                       "properties": {
+                                                               "idle_timeout": 
{
+                                                                       
"default": 60,
+                                                                       
"minimum": 0,
+                                                                       "type": 
"number"
+                                                               },
+                                                               "requests": {
+                                                                       
"default": 1000,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               },
+                                                               "size": {
+                                                                       
"default": 320,
+                                                                       
"minimum": 1,
+                                                                       "type": 
"integer"
+                                                               }
+                                                       },
+                                                       "type": "object"
+                                               },
                                                "key": {
                                                        "description": "the key 
of chash for dynamic load balancing",
                                                        "type": "string"
@@ -1753,6 +1805,10 @@
                                                        "minimum": 0,
                                                        "type": "integer"
                                                },
+                                               "retry_timeout": {
+                                                       "minimum": 0,
+                                                       "type": "number"
+                                               },
                                                "scheme": {
                                                        "default": "http",
                                                        "enum": ["grpc", 
"grpcs", "http", "https"]
@@ -1798,7 +1854,6 @@
                                                },
                                                "type": {
                                                        "description": 
"algorithms of load balancing",
-                                                       "enum": ["chash", 
"ewma", "least_conn", "roundrobin"],
                                                        "type": "string"
                                                },
                                                "update_time": {
@@ -1826,7 +1881,6 @@
                        "type": "object"
                },
                "upstream": {
-                       "additionalProperties": false,
                        "oneOf": [{
                                "required": ["nodes", "type"]
                        }, {
@@ -1834,7 +1888,6 @@
                        }],
                        "properties": {
                                "checks": {
-                                       "additionalProperties": false,
                                        "anyOf": [{
                                                "required": ["active"]
                                        }, {
@@ -2059,6 +2112,26 @@
                                                "type": "integer"
                                        }]
                                },
+                               "keepalive_pool": {
+                                       "properties": {
+                                               "idle_timeout": {
+                                                       "default": 60,
+                                                       "minimum": 0,
+                                                       "type": "number"
+                                               },
+                                               "requests": {
+                                                       "default": 1000,
+                                                       "minimum": 1,
+                                                       "type": "integer"
+                                               },
+                                               "size": {
+                                                       "default": 320,
+                                                       "minimum": 1,
+                                                       "type": "integer"
+                                               }
+                                       },
+                                       "type": "object"
+                               },
                                "key": {
                                        "description": "the key of chash for 
dynamic load balancing",
                                        "type": "string"
@@ -2135,6 +2208,10 @@
                                        "minimum": 0,
                                        "type": "integer"
                                },
+                               "retry_timeout": {
+                                       "minimum": 0,
+                                       "type": "number"
+                               },
                                "scheme": {
                                        "default": "http",
                                        "enum": ["grpc", "grpcs", "http", 
"https"]
@@ -2180,7 +2257,6 @@
                                },
                                "type": {
                                        "description": "algorithms of load 
balancing",
-                                       "enum": ["chash", "ewma", "least_conn", 
"roundrobin"],
                                        "type": "string"
                                },
                                "update_time": {
@@ -2277,6 +2353,51 @@
                        },
                        "version": 0.1
                },
+               "authz-casbin": {
+                       "metadata_schema": {
+                               "properties": {
+                                       "model": {
+                                               "type": "string"
+                                       },
+                                       "policy": {
+                                               "type": "string"
+                                       }
+                               },
+                               "required": ["model", "policy"],
+                               "type": "object"
+                       },
+                       "priority": 2560,
+                       "schema": {
+                               "$comment": "this is a mark for our injected 
plugin schema",
+                               "oneOf": [{
+                                       "required": ["model_path", 
"policy_path", "username"]
+                               }, {
+                                       "required": ["model", "policy", 
"username"]
+                               }],
+                               "properties": {
+                                       "disable": {
+                                               "type": "boolean"
+                                       },
+                                       "model": {
+                                               "type": "string"
+                                       },
+                                       "model_path": {
+                                               "type": "string"
+                                       },
+                                       "policy": {
+                                               "type": "string"
+                                       },
+                                       "policy_path": {
+                                               "type": "string"
+                                       },
+                                       "username": {
+                                               "type": "string"
+                                       }
+                               },
+                               "type": "object"
+                       },
+                       "version": 0.1
+               },
                "authz-keycloak": {
                        "priority": 2000,
                        "schema": {
@@ -2373,6 +2494,7 @@
                                                "type": "boolean"
                                        },
                                        "permissions": {
+                                               "default": {},
                                                "items": {
                                                        "maxLength": 100,
                                                        "minLength": 1,
@@ -2412,7 +2534,6 @@
                },
                "basic-auth": {
                        "consumer_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "password": {
                                                "type": "string"
@@ -2428,7 +2549,6 @@
                        "priority": 2520,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -2442,7 +2562,6 @@
                },
                "batch-requests": {
                        "metadata_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "max_body_size": {
                                                "default": 1048576,
@@ -2456,7 +2575,6 @@
                        "priority": 4010,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -2532,7 +2650,7 @@
                                        },
                                        "type": {
                                                "default": "consumer_name",
-                                               "enum": ["consumer_name", 
"service_id"],
+                                               "enum": ["consumer_name", 
"route_id", "service_id"],
                                                "type": "string"
                                        },
                                        "whitelist": {
@@ -2570,6 +2688,7 @@
                                        "allow_origins": {
                                                "default": "*",
                                                "description": "you can use '*' 
to allow all origins when no credentials,'**' to allow forcefully(it will bring 
some security risks, be carefully),multiple origin use ',' to split. default: 
*.",
+                                               "pattern": 
"^(\\*|\\*\\*|null|\\w+://[^,]+(,\\w+://[^,]+)*)$",
                                                "type": "string"
                                        },
                                        "allow_origins_by_regex": {
@@ -2631,7 +2750,6 @@
                        "priority": 412,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "anyOf": [{
                                        "required": ["before_body"]
                                }, {
@@ -2746,7 +2864,6 @@
                },
                "example-plugin": {
                        "metadata_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "ikey": {
                                                "minimum": 0,
@@ -2976,9 +3093,71 @@
                        },
                        "version": 0.1
                },
+               "gzip": {
+                       "priority": 995,
+                       "schema": {
+                               "$comment": "this is a mark for our injected 
plugin schema",
+                               "properties": {
+                                       "buffers": {
+                                               "default": {
+                                                       "number": 32,
+                                                       "size": 4096
+                                               },
+                                               "properties": {
+                                                       "number": {
+                                                               "default": 32,
+                                                               "minimum": 1,
+                                                               "type": 
"integer"
+                                                       },
+                                                       "size": {
+                                                               "default": 4096,
+                                                               "minimum": 1,
+                                                               "type": 
"integer"
+                                                       }
+                                               },
+                                               "type": "object"
+                                       },
+                                       "comp_level": {
+                                               "default": 1,
+                                               "maximum": 9,
+                                               "minimum": 1,
+                                               "type": "integer"
+                                       },
+                                       "disable": {
+                                               "type": "boolean"
+                                       },
+                                       "http_version": {
+                                               "default": 1.1,
+                                               "enum": [1, 1.1]
+                                       },
+                                       "min_length": {
+                                               "default": 20,
+                                               "minimum": 1,
+                                               "type": "integer"
+                                       },
+                                       "types": {
+                                               "anyOf": [{
+                                                       "items": {
+                                                               "minLength": 1,
+                                                               "type": "string"
+                                                       },
+                                                       "minItem": 1,
+                                                       "type": "array"
+                                               }, {
+                                                       "enum": ["*"]
+                                               }],
+                                               "default": ["text/html"]
+                                       },
+                                       "vary": {
+                                               "type": "boolean"
+                                       }
+                               },
+                               "type": "object"
+                       },
+                       "version": 0.1
+               },
                "hmac-auth": {
                        "consumer_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "access_key": {
                                                "maxLength": 256,
@@ -3025,7 +3204,6 @@
                        "priority": 2530,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -3039,7 +3217,6 @@
                },
                "http-logger": {
                        "metadata_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "log_format": {
                                                "default": {
@@ -3121,67 +3298,65 @@
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
                                "oneOf": [{
-                                       "additionalProperties": false,
-                                       "properties": {
-                                               "whitelist": {
-                                                       "items": {
-                                                               "anyOf": [{
-                                                                       
"format": "ipv4",
-                                                                       
"title": "IPv4",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"pattern": 
"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$",
-                                                                       
"title": "IPv4/CIDR",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"format": "ipv6",
-                                                                       
"title": "IPv6",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"pattern": 
"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$",
-                                                                       
"title": "IPv6/CIDR",
-                                                                       "type": 
"string"
-                                                               }]
-                                                       },
-                                                       "minItems": 1,
-                                                       "type": "array"
-                                               }
-                                       },
-                                       "required": ["whitelist"],
-                                       "title": "whitelist"
+                                       "required": ["whitelist"]
                                }, {
-                                       "additionalProperties": false,
-                                       "properties": {
-                                               "blacklist": {
-                                                       "items": {
-                                                               "anyOf": [{
-                                                                       
"format": "ipv4",
-                                                                       
"title": "IPv4",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"pattern": 
"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$",
-                                                                       
"title": "IPv4/CIDR",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"format": "ipv6",
-                                                                       
"title": "IPv6",
-                                                                       "type": 
"string"
-                                                               }, {
-                                                                       
"pattern": 
"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$",
-                                                                       
"title": "IPv6/CIDR",
-                                                                       "type": 
"string"
-                                                               }]
-                                                       },
-                                                       "minItems": 1,
-                                                       "type": "array"
-                                               }
-                                       },
-                                       "required": ["blacklist"],
-                                       "title": "blacklist"
+                                       "required": ["blacklist"]
                                }],
                                "properties": {
+                                       "blacklist": {
+                                               "items": {
+                                                       "anyOf": [{
+                                                               "format": 
"ipv4",
+                                                               "title": "IPv4",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$",
+                                                               "title": 
"IPv4/CIDR",
+                                                               "type": "string"
+                                                       }, {
+                                                               "format": 
"ipv6",
+                                                               "title": "IPv6",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$",
+                                                               "title": 
"IPv6/CIDR",
+                                                               "type": "string"
+                                                       }]
+                                               },
+                                               "minItems": 1,
+                                               "type": "array"
+                                       },
                                        "disable": {
                                                "type": "boolean"
+                                       },
+                                       "message": {
+                                               "default": "Your IP address is 
not allowed",
+                                               "maxLength": 1024,
+                                               "minLength": 1,
+                                               "type": "string"
+                                       },
+                                       "whitelist": {
+                                               "items": {
+                                                       "anyOf": [{
+                                                               "format": 
"ipv4",
+                                                               "title": "IPv4",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$",
+                                                               "title": 
"IPv4/CIDR",
+                                                               "type": "string"
+                                                       }, {
+                                                               "format": 
"ipv6",
+                                                               "title": "IPv6",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$",
+                                                               "title": 
"IPv6/CIDR",
+                                                               "type": "string"
+                                                       }]
+                                               },
+                                               "minItems": 1,
+                                               "type": "array"
                                        }
                                },
                                "type": "object"
@@ -3243,7 +3418,6 @@
                        "priority": 2510,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -3255,6 +3429,19 @@
                        "version": 0.1
                },
                "kafka-logger": {
+                       "metadata_schema": {
+                               "properties": {
+                                       "log_format": {
+                                               "default": {
+                                                       "@timestamp": 
"$time_iso8601",
+                                                       "client_ip": 
"$remote_addr",
+                                                       "host": "$host"
+                                               },
+                                               "type": "object"
+                                       }
+                               },
+                               "type": "object"
+                       },
                        "priority": 403,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
@@ -3327,7 +3514,6 @@
                },
                "key-auth": {
                        "consumer_schema": {
-                               "additionalProperties": false,
                                "properties": {
                                        "key": {
                                                "type": "string"
@@ -3339,7 +3525,6 @@
                        "priority": 2500,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -3347,6 +3532,10 @@
                                        "header": {
                                                "default": "apikey",
                                                "type": "string"
+                                       },
+                                       "query": {
+                                               "default": "apikey",
+                                               "type": "string"
                                        }
                                },
                                "type": "object"
@@ -3375,14 +3564,12 @@
                                                "type": "boolean"
                                        },
                                        "key": {
-                                               "enum": ["consumer_name", 
"http_x_forwarded_for", "http_x_real_ip", "remote_addr", "server_addr"],
+                                               "enum": ["remote_addr", 
"server_addr"],
                                                "type": "string"
                                        },
-                                       "rejected_code": {
-                                               "default": 503,
-                                               "maximum": 599,
-                                               "minimum": 200,
-                                               "type": "integer"
+                                       "only_use_default_delay": {
+                                               "default": false,
+                                               "type": "boolean"
                                        }
                                },
                                "required": ["burst", "conn", 
"default_conn_delay", "key"],
@@ -3464,6 +3651,10 @@
                                        }
                                },
                                "properties": {
+                                       "allow_degradation": {
+                                               "default": false,
+                                               "type": "boolean"
+                                       },
                                        "count": {
                                                "exclusiveMinimum": 0,
                                                "type": "integer"
@@ -3487,6 +3678,14 @@
                                                "minimum": 200,
                                                "type": "integer"
                                        },
+                                       "rejected_msg": {
+                                               "minLength": 1,
+                                               "type": "string"
+                                       },
+                                       "show_limit_quota_header": {
+                                               "default": true,
+                                               "type": "boolean"
+                                       },
                                        "time_window": {
                                                "exclusiveMinimum": 0,
                                                "type": "integer"
@@ -3502,6 +3701,10 @@
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
                                "properties": {
+                                       "allow_degradation": {
+                                               "default": false,
+                                               "type": "boolean"
+                                       },
                                        "burst": {
                                                "minimum": 0,
                                                "type": "number"
@@ -3526,6 +3729,10 @@
                                                "maximum": 599,
                                                "minimum": 200,
                                                "type": "integer"
+                                       },
+                                       "rejected_msg": {
+                                               "minLength": 1,
+                                               "type": "string"
                                        }
                                },
                                "required": ["burst", "key", "rate"],
@@ -3690,7 +3897,6 @@
                        "priority": 500,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -3742,8 +3948,8 @@
                                        "cache_method": {
                                                "default": ["GET", "HEAD"],
                                                "items": {
-                                                       "description": "HTTP 
method",
-                                                       "enum": ["CONNECT", 
"DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"],
+                                                       "description": 
"supported http method",
+                                                       "enum": ["GET", "HEAD", 
"POST"],
                                                        "type": "string"
                                                },
                                                "minItems": 1,
@@ -3799,7 +4005,6 @@
                        "priority": 1008,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "minProperties": 1,
                                "properties": {
                                        "disable": {
@@ -3842,6 +4047,47 @@
                        },
                        "version": 0.1
                },
+               "real-ip": {
+                       "priority": 23000,
+                       "schema": {
+                               "$comment": "this is a mark for our injected 
plugin schema",
+                               "properties": {
+                                       "disable": {
+                                               "type": "boolean"
+                                       },
+                                       "source": {
+                                               "minLength": 1,
+                                               "type": "string"
+                                       },
+                                       "trusted_addresses": {
+                                               "items": {
+                                                       "anyOf": [{
+                                                               "format": 
"ipv4",
+                                                               "title": "IPv4",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/([12]?[0-9]|3[0-2])$",
+                                                               "title": 
"IPv4/CIDR",
+                                                               "type": "string"
+                                                       }, {
+                                                               "format": 
"ipv6",
+                                                               "title": "IPv6",
+                                                               "type": "string"
+                                                       }, {
+                                                               "pattern": 
"^([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?/[0-9]{1,3}$",
+                                                               "title": 
"IPv6/CIDR",
+                                                               "type": "string"
+                                                       }]
+                                               },
+                                               "minItems": 1,
+                                               "type": "array"
+                                       }
+                               },
+                               "required": ["source"],
+                               "type": "object"
+                       },
+                       "version": 0.1
+               },
                "redirect": {
                        "priority": 900,
                        "schema": {
@@ -3897,7 +4143,6 @@
                        "priority": 2990,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "bypass_missing": {
                                                "default": false,
@@ -3925,6 +4170,11 @@
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
                                "properties": {
+                                       "algorithm": {
+                                               "default": "uuid",
+                                               "enum": ["snowflake", "uuid"],
+                                               "type": "string"
+                                       },
                                        "disable": {
                                                "type": "boolean"
                                        },
@@ -3976,7 +4226,6 @@
                        "priority": 899,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "minProperties": 1,
                                "properties": {
                                        "body": {
@@ -4014,7 +4263,6 @@
                        "priority": 990,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
@@ -4335,14 +4583,12 @@
                        "priority": 966,
                        "schema": {
                                "$comment": "this is a mark for our injected 
plugin schema",
-                               "additionalProperties": false,
                                "properties": {
                                        "disable": {
                                                "type": "boolean"
                                        },
                                        "rules": {
                                                "items": {
-                                                       "additionalProperties": 
false,
                                                        "properties": {
                                                                "match": {
                                                                        
"items": {
@@ -4362,7 +4608,6 @@
                                                                        
"items": {
                                                                                
"properties": {
                                                                                
        "upstream": {
-                                                                               
                "additionalProperties": false,
                                                                                
                "oneOf": [{
                                                                                
                        "required": ["nodes", "type"]
                                                                                
                }, {
@@ -4370,7 +4615,6 @@
                                                                                
                }],
                                                                                
                "properties": {
                                                                                
                        "checks": {
-                                                                               
                                "additionalProperties": false,
                                                                                
                                "anyOf": [{
                                                                                
                                        "required": ["active"]
                                                                                
                                }, {
@@ -4595,6 +4839,26 @@
                                                                                
                                        "type": "integer"
                                                                                
                                }]
                                                                                
                        },
+                                                                               
                        "keepalive_pool": {
+                                                                               
                                "properties": {
+                                                                               
                                        "idle_timeout": {
+                                                                               
                                                "default": 60,
+                                                                               
                                                "minimum": 0,
+                                                                               
                                                "type": "number"
+                                                                               
                                        },
+                                                                               
                                        "requests": {
+                                                                               
                                                "default": 1000,
+                                                                               
                                                "minimum": 1,
+                                                                               
                                                "type": "integer"
+                                                                               
                                        },
+                                                                               
                                        "size": {
+                                                                               
                                                "default": 320,
+                                                                               
                                                "minimum": 1,
+                                                                               
                                                "type": "integer"
+                                                                               
                                        }
+                                                                               
                                },
+                                                                               
                                "type": "object"
+                                                                               
                        },
                                                                                
                        "key": {
                                                                                
                                "description": "the key of chash for dynamic 
load balancing",
                                                                                
                                "type": "string"
@@ -4671,6 +4935,10 @@
                                                                                
                                "minimum": 0,
                                                                                
                                "type": "integer"
                                                                                
                        },
+                                                                               
                        "retry_timeout": {
+                                                                               
                                "minimum": 0,
+                                                                               
                                "type": "number"
+                                                                               
                        },
                                                                                
                        "scheme": {
                                                                                
                                "default": "http",
                                                                                
                                "enum": ["grpc", "grpcs", "http", "https"]
@@ -4716,7 +4984,6 @@
                                                                                
                        },
                                                                                
                        "type": {
                                                                                
                                "description": "algorithms of load balancing",
-                                                                               
                                "enum": ["chash", "ewma", "least_conn", 
"roundrobin"],
                                                                                
                                "type": "string"
                                                                                
                        },
                                                                                
                        "update_time": {
@@ -4763,6 +5030,37 @@
                        },
                        "version": 0.1
                },
+               "ua-restriction": {
+                       "priority": 2999,
+                       "schema": {
+                               "$comment": "this is a mark for our injected 
plugin schema",
+                               "properties": {
+                                       "allowlist": {
+                                               "minItems": 1,
+                                               "type": "array"
+                                       },
+                                       "bypass_missing": {
+                                               "default": false,
+                                               "type": "boolean"
+                                       },
+                                       "denylist": {
+                                               "minItems": 1,
+                                               "type": "array"
+                                       },
+                                       "disable": {
+                                               "type": "boolean"
+                                       },
+                                       "message": {
+                                               "default": "Not allowed",
+                                               "maxLength": 1024,
+                                               "minLength": 1,
+                                               "type": "string"
+                                       }
+                               },
+                               "type": "object"
+                       },
+                       "version": 0.1
+               },
                "udp-logger": {
                        "priority": 400,
                        "schema": {
@@ -4833,6 +5131,10 @@
                                                "default": 403,
                                                "minimum": 200,
                                                "type": "integer"
+                                       },
+                                       "rejected_msg": {
+                                               "minLength": 1,
+                                               "type": "string"
                                        }
                                },
                                "required": ["block_rules"],
diff --git a/api/internal/core/entity/entity.go 
b/api/internal/core/entity/entity.go
index efa10be..1d17c9a 100644
--- a/api/internal/core/entity/entity.go
+++ b/api/internal/core/entity/entity.go
@@ -97,10 +97,11 @@ type Route struct {
 }
 
 // --- structures for upstream start  ---
+type TimeoutValue float32
 type Timeout struct {
-       Connect int `json:"connect,omitempty"`
-       Send    int `json:"send,omitempty"`
-       Read    int `json:"read,omitempty"`
+       Connect TimeoutValue `json:"connect,omitempty"`
+       Send    TimeoutValue `json:"send,omitempty"`
+       Read    TimeoutValue `json:"read,omitempty"`
 }
 
 type Node struct {
@@ -133,16 +134,16 @@ type UnHealthy struct {
 }
 
 type Active struct {
-       Type                   string    `json:"type,omitempty"`
-       Timeout                int       `json:"timeout,omitempty"`
-       Concurrency            int       `json:"concurrency,omitempty"`
-       Host                   string    `json:"host,omitempty"`
-       Port                   int       `json:"port,omitempty"`
-       HTTPPath               string    `json:"http_path,omitempty"`
-       HTTPSVerifyCertificate string    
`json:"https_verify_certificate,omitempty"`
-       Healthy                Healthy   `json:"healthy,omitempty"`
-       UnHealthy              UnHealthy `json:"unhealthy,omitempty"`
-       ReqHeaders             []string  `json:"req_headers,omitempty"`
+       Type                   string       `json:"type,omitempty"`
+       Timeout                TimeoutValue `json:"timeout,omitempty"`
+       Concurrency            int          `json:"concurrency,omitempty"`
+       Host                   string       `json:"host,omitempty"`
+       Port                   int          `json:"port,omitempty"`
+       HTTPPath               string       `json:"http_path,omitempty"`
+       HTTPSVerifyCertificate string       
`json:"https_verify_certificate,omitempty"`
+       Healthy                Healthy      `json:"healthy,omitempty"`
+       UnHealthy              UnHealthy    `json:"unhealthy,omitempty"`
+       ReqHeaders             []string     `json:"req_headers,omitempty"`
 }
 
 type Passive struct {
@@ -161,24 +162,32 @@ type UpstreamTLS struct {
        ClientKey  string `json:"client_key,omitempty"`
 }
 
+type UpstreamKeepalivePool struct {
+       IdleTimeout TimeoutValue `json:"idle_timeout,omitempty"`
+       Requests    int          `json:"requests,omitempty"`
+       Size        int          `json:"size"`
+}
+
 type UpstreamDef struct {
-       Nodes         interface{}       `json:"nodes,omitempty"`
-       Retries       int               `json:"retries,omitempty"`
-       Timeout       interface{}       `json:"timeout,omitempty"`
-       Type          string            `json:"type,omitempty"`
-       Checks        interface{}       `json:"checks,omitempty"`
-       HashOn        string            `json:"hash_on,omitempty"`
-       Key           string            `json:"key,omitempty"`
-       Scheme        string            `json:"scheme,omitempty"`
-       DiscoveryType string            `json:"discovery_type,omitempty"`
-       DiscoveryArgs map[string]string `json:"discovery_args,omitempty"`
-       PassHost      string            `json:"pass_host,omitempty"`
-       UpstreamHost  string            `json:"upstream_host,omitempty"`
-       Name          string            `json:"name,omitempty"`
-       Desc          string            `json:"desc,omitempty"`
-       ServiceName   string            `json:"service_name,omitempty"`
-       Labels        map[string]string `json:"labels,omitempty"`
-       TLS           *UpstreamTLS      `json:"tls,omitempty"`
+       Nodes         interface{}            `json:"nodes,omitempty"`
+       Retries       int                    `json:"retries,omitempty"`
+       Timeout       *Timeout               `json:"timeout,omitempty"`
+       Type          string                 `json:"type,omitempty"`
+       Checks        interface{}            `json:"checks,omitempty"`
+       HashOn        string                 `json:"hash_on,omitempty"`
+       Key           string                 `json:"key,omitempty"`
+       Scheme        string                 `json:"scheme,omitempty"`
+       DiscoveryType string                 `json:"discovery_type,omitempty"`
+       DiscoveryArgs map[string]string      `json:"discovery_args,omitempty"`
+       PassHost      string                 `json:"pass_host,omitempty"`
+       UpstreamHost  string                 `json:"upstream_host,omitempty"`
+       Name          string                 `json:"name,omitempty"`
+       Desc          string                 `json:"desc,omitempty"`
+       ServiceName   string                 `json:"service_name,omitempty"`
+       Labels        map[string]string      `json:"labels,omitempty"`
+       TLS           *UpstreamTLS           `json:"tls,omitempty"`
+       KeepalivePool *UpstreamKeepalivePool `json:"keepalive_pool,omitempty"`
+       RetryTimeout  TimeoutValue           `json:"retry_timeout,omitempty"`
 }
 
 // swagger:model Upstream
diff --git a/api/internal/core/store/validate_test.go 
b/api/internal/core/store/validate_test.go
index 7b0b6f3..8050499 100644
--- a/api/internal/core/store/validate_test.go
+++ b/api/internal/core/store/validate_test.go
@@ -289,7 +289,7 @@ func TestAPISIXJsonSchemaValidator_Plugin(t *testing.T) {
        err = json.Unmarshal([]byte(reqBody), route)
        assert.Nil(t, err)
        err = validator.Validate(route)
-       assert.Equal(t, fmt.Errorf("schema validate failed: (root): Must 
validate one and only one schema (oneOf)\n(root): Additional property disable 
is not allowed\ndisable: Invalid type. Expected: boolean, given: integer"), err)
+       assert.Equal(t, fmt.Errorf("schema validate failed: disable: Invalid 
type. Expected: boolean, given: integer"), err)
 }
 
 func TestAPISIXJsonSchemaValidator_Route_checkRemoteAddr(t *testing.T) {
@@ -447,23 +447,4 @@ func TestAPISIXSchemaValidator_Validate(t *testing.T) {
        }`
        err = validator.Validate([]byte(reqBody))
        assert.Nil(t, err)
-
-       // config with non existent field, should be failed.
-       reqBody = `{
-               "username": "jack",
-               "not-exist": "val",
-               "plugins": {
-                       "limit-count": {
-                               "count": 2,
-                               "time_window": 60,
-                               "rejected_code": 503,
-                               "key": "remote_addr"
-                       }
-               },
-               "desc": "test description"
-       }`
-       err = validator.Validate([]byte(reqBody))
-       assert.NotNil(t, err)
-       assert.EqualError(t, err, "schema validate failed: (root): Additional 
property not-exist is not allowed")
-
 }
diff --git a/api/internal/handler/schema/plugin_test.go 
b/api/internal/handler/schema/plugin_test.go
index d569f2d..eb61e79 100644
--- a/api/internal/handler/schema/plugin_test.go
+++ b/api/internal/handler/schema/plugin_test.go
@@ -62,5 +62,5 @@ func TestPlugin(t *testing.T) {
        // plugin type
        assert.ElementsMatch(t, []string{"basic-auth", "jwt-auth", "hmac-auth", 
"key-auth", "wolf-rbac"}, authPlugins)
        // consumer schema
-       assert.Equal(t, 
`{"additionalProperties":false,"properties":{"password":{"type":"string"},"username":{"type":"string"}},"required":["password","username"],"title":"work
 with consumer object","type":"object"}`, basicAuthConsumerSchema)
+       assert.Equal(t, 
`{"properties":{"password":{"type":"string"},"username":{"type":"string"}},"required":["password","username"],"title":"work
 with consumer object","type":"object"}`, basicAuthConsumerSchema)
 }
diff --git a/api/internal/handler/upstream/upstream_test.go 
b/api/internal/handler/upstream/upstream_test.go
index c2b274d..47c219a 100644
--- a/api/internal/handler/upstream/upstream_test.go
+++ b/api/internal/handler/upstream/upstream_test.go
@@ -55,10 +55,10 @@ func TestUpstream_Get(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -103,10 +103,10 @@ func TestUpstream_Get(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -345,10 +345,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -393,10 +393,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -441,10 +441,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -489,10 +489,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -542,10 +542,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -591,10 +591,10 @@ func TestUpstream_Create(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -689,10 +689,10 @@ func TestUpstream_Update(t *testing.T) {
                                Upstream: entity.Upstream{
                                        UpstreamDef: entity.UpstreamDef{
                                                Name: "upstream1",
-                                               Timeout: map[string]interface{}{
-                                                       "connect": 15,
-                                                       "send":    15,
-                                                       "read":    15,
+                                               Timeout: &entity.Timeout{
+                                                       Connect: 15,
+                                                       Send:    15,
+                                                       Read:    15,
                                                },
                                                Checks: map[string]interface{}{
                                                        "active": 
map[string]interface{}{
@@ -738,10 +738,10 @@ func TestUpstream_Update(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -786,10 +786,10 @@ func TestUpstream_Update(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -834,10 +834,10 @@ func TestUpstream_Update(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": 15,
-                                               "send":    15,
-                                               "read":    15,
+                                       Timeout: &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -887,10 +887,10 @@ func TestUpstream_Update(t *testing.T) {
                                        },
                                        UpstreamDef: entity.UpstreamDef{
                                                Name: "upstream1",
-                                               Timeout: map[string]interface{}{
-                                                       "connect": 15,
-                                                       "send":    15,
-                                                       "read":    15,
+                                               Timeout: &entity.Timeout{
+                                                       Connect: 15,
+                                                       Send:    15,
+                                                       Read:    15,
                                                },
                                                Checks: map[string]interface{}{
                                                        "active": 
map[string]interface{}{
@@ -973,10 +973,10 @@ func TestUpstream_Patch(t *testing.T) {
                },
                UpstreamDef: entity.UpstreamDef{
                        Name: "upstream1",
-                       Timeout: map[string]interface{}{
-                               "connect": 15,
-                               "send":    15,
-                               "read":    15,
+                       Timeout: &entity.Timeout{
+                               Connect: 15,
+                               Send:    15,
+                               Read:    15,
                        },
                        Checks: map[string]interface{}{
                                "active": map[string]interface{}{
@@ -1022,10 +1022,10 @@ func TestUpstream_Patch(t *testing.T) {
                },
                UpstreamDef: entity.UpstreamDef{
                        Name: "upstream2",
-                       Timeout: map[string]interface{}{
-                               "connect": float64(20),
-                               "send":    float64(20),
-                               "read":    float64(20),
+                       Timeout: &entity.Timeout{
+                               Connect: 20,
+                               Send:    20,
+                               Read:    20,
                        },
                        Checks: map[string]interface{}{
                                "active": map[string]interface{}{
@@ -1085,10 +1085,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream2",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(20),
-                                               "send":    float64(20),
-                                               "read":    float64(20),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 20,
+                                               Send:    20,
+                                               Read:    20,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -1138,10 +1138,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream2",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(20),
-                                               "send":    float64(20),
-                                               "read":    float64(20),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 20,
+                                               Send:    20,
+                                               Read:    20,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -1186,10 +1186,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream2",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(20),
-                                               "send":    float64(20),
-                                               "read":    float64(20),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 20,
+                                               Send:    20,
+                                               Read:    20,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -1243,10 +1243,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(20),
-                                               "send":    float64(20),
-                                               "read":    float64(20),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 20,
+                                               Send:    20,
+                                               Read:    20,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -1291,10 +1291,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(15),
-                                               "send":    float64(15),
-                                               "read":    float64(15),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 15,
+                                               Send:    15,
+                                               Read:    15,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
@@ -1339,10 +1339,10 @@ func TestUpstream_Patch(t *testing.T) {
                                },
                                UpstreamDef: entity.UpstreamDef{
                                        Name: "upstream1",
-                                       Timeout: map[string]interface{}{
-                                               "connect": float64(20),
-                                               "send":    float64(20),
-                                               "read":    float64(20),
+                                       Timeout:  &entity.Timeout{
+                                               Connect: 20,
+                                               Send:    20,
+                                               Read:    20,
                                        },
                                        Checks: map[string]interface{}{
                                                "active": 
map[string]interface{}{
diff --git a/api/test/docker/docker-compose.yaml 
b/api/test/docker/docker-compose.yaml
index 3f85c51..072f312 100644
--- a/api/test/docker/docker-compose.yaml
+++ b/api/test/docker/docker-compose.yaml
@@ -127,7 +127,7 @@ services:
 
   apisix:
     hostname: apisix_server1
-    image: apache/apisix:2.7-alpine
+    image: apache/apisix:2.9-alpine
     restart: always
     volumes:
       - ./apisix_config.yaml:/usr/local/apisix/conf/config.yaml:ro
diff --git a/api/test/e2e/json_schema_validate_test.go 
b/api/test/e2e/json_schema_validate_test.go
deleted file mode 100644
index df46742..0000000
--- a/api/test/e2e/json_schema_validate_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package e2e
-
-import (
-       "net/http"
-       "testing"
-)
-
-func TestSchema_not_exist_field(t *testing.T) {
-       tests := []HttpTestCase{
-               {
-                       Desc:   "config route with non-existent fields",
-                       Object: ManagerApiExpect(t),
-                       Path:   "/apisix/admin/routes/r1",
-                       Method: http.MethodPut,
-                       Body: `{
-                               "name": "route1",
-                                "uri": "/hello",
-                                "nonexistent": "test non-existent",
-                                "upstream": {
-                                        "type": "roundrobin",
-                                        "nodes": [{
-                                                "host": "` + UpstreamIp + `",
-                                                "port": 1980,
-                                                "weight": 1
-                                        }]
-                                }
-                        }`,
-                       Headers:      map[string]string{"Authorization": token},
-                       ExpectStatus: http.StatusBadRequest,
-                       ExpectBody:   `{"code":10000,"message":"schema validate 
failed: (root): Additional property nonexistent is not allowed"}`,
-               },
-               {
-                       Desc:         "make sure the route create failed",
-                       Object:       APISIXExpect(t),
-                       Method:       http.MethodGet,
-                       Path:         "/hello",
-                       ExpectStatus: http.StatusNotFound,
-                       Sleep:        sleepTime,
-               },
-       }
-
-       for _, tc := range tests {
-               testCaseCheck(tc, t)
-       }
-}
diff --git a/api/test/e2e/route_import_test.go 
b/api/test/e2e/route_import_test.go
index bb70562..b482688 100644
--- a/api/test/e2e/route_import_test.go
+++ b/api/test/e2e/route_import_test.go
@@ -319,7 +319,7 @@ func TestImport_with_multi_routes(t *testing.T) {
                                ExpectBody: 
[]string{`"methods":["GET","POST","HEAD","PUT","PATCH","DELETE"]`,
                                        
`"proxy-rewrite":{"disable":false,"scheme":"https"}`,
                                        
`"labels":{"API_VERSION":"v2","dev":"test"}`,
-                                       
`"upstream":{"nodes":[{"host":"httpbin.org","port":443,"weight":1}],"timeout":{"connect":6000,"read":6000,"send":6000},"type":"roundrobin","pass_host":"node"}`,
+                                       
`"upstream":{"nodes":[{"host":"httpbin.org","port":443,"weight":1}],"timeout":{"connect":6000,"send":6000,"read":6000},"type":"roundrobin","pass_host":"node"}`,
                                },
                                Sleep: sleepTime,
                        }
@@ -335,7 +335,7 @@ func TestImport_with_multi_routes(t *testing.T) {
                                ExpectBody: []string{`"methods":["POST"]`,
                                        
`"proxy-rewrite":{"disable":false,"scheme":"https"}`,
                                        
`"labels":{"API_VERSION":"v1","version":"v1"}`,
-                                       
`"upstream":{"nodes":[{"host":"httpbin.org","port":443,"weight":1}],"timeout":{"connect":6000,"read":6000,"send":6000},"type":"roundrobin","pass_host":"node"}`,
+                                       
`"upstream":{"nodes":[{"host":"httpbin.org","port":443,"weight":1}],"timeout":{"connect":6000,"send":6000,"read":6000},"type":"roundrobin","pass_host":"node"}`,
                                },
                                Sleep: sleepTime,
                        }
diff --git a/api/test/e2enew/schema/schema_test.go 
b/api/test/e2enew/schema/schema_test.go
index 50a55d3..febb3c7 100644
--- a/api/test/e2enew/schema/schema_test.go
+++ b/api/test/e2enew/schema/schema_test.go
@@ -52,7 +52,7 @@ var _ = ginkgo.Describe("Schema Test", func() {
                        Path:         "/apisix/admin/schema/plugins/jwt-auth",
                        Headers:      map[string]string{"Authorization": 
base.GetToken()},
                        ExpectStatus: http.StatusOK,
-                       ExpectBody:   "{\"$comment\":\"this is a mark for our 
injected plugin 
schema\",\"additionalProperties\":false,\"properties\":{\"disable\":{\"type\":\"boolean\"}},\"type\":\"object\"}",
+                       ExpectBody:   "{\"$comment\":\"this is a mark for our 
injected plugin 
schema\",\"properties\":{\"disable\":{\"type\":\"boolean\"}},\"type\":\"object\"}",
                        Sleep:        base.SleepTime,
                }),
                table.Entry("get schema of non-existent plugin", 
base.HttpTestCase{
diff --git a/api/test/e2enew/upstream/upstream_keepalive_pool.go 
b/api/test/e2enew/upstream/upstream_keepalive_pool.go
new file mode 100644
index 0000000..9047ac3
--- /dev/null
+++ b/api/test/e2enew/upstream/upstream_keepalive_pool.go
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package upstream
+
+import (
+       "encoding/json"
+       "net/http"
+
+       "github.com/onsi/ginkgo"
+       "github.com/onsi/gomega"
+
+       "github.com/apisix/manager-api/test/e2enew/base"
+)
+
+// just test for schema check
+var _ = ginkgo.Describe("Upstream keepalive pool", func() {
+       ginkgo.It("create upstream with keepalive pool", func() {
+               createUpstreamBody := make(map[string]interface{})
+               createUpstreamBody["nodes"] = []map[string]interface{}{
+                       {
+                               "host":   base.UpstreamIp,
+                               "port":   1980,
+                               "weight": 1,
+                       },
+               }
+               createUpstreamBody["type"] = "roundrobin"
+               createUpstreamBody["keepalive_pool"] = map[string]interface{}{
+                       "size": 320,
+                       "requests": 1000,
+                       "idle_timeout": 60,
+               }
+               _createUpstreamBody, err := json.Marshal(createUpstreamBody)
+               gomega.Expect(err).To(gomega.BeNil())
+               base.RunTestCase(base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodPut,
+                       Path:         "/apisix/admin/upstreams/kp",
+                       Body:         string(_createUpstreamBody),
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+               })
+       })
+       ginkgo.It("delete upstream", func() {
+               base.RunTestCase(base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodDelete,
+                       Path:         "/apisix/admin/upstreams/kp",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+               })
+       })
+})
diff --git a/api/test/e2enew/upstream/upstream_retry.go 
b/api/test/e2enew/upstream/upstream_retry.go
new file mode 100644
index 0000000..adb81bb
--- /dev/null
+++ b/api/test/e2enew/upstream/upstream_retry.go
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package upstream
+
+import (
+       "encoding/json"
+       "net/http"
+
+       "github.com/onsi/ginkgo"
+       "github.com/onsi/gomega"
+
+       "github.com/apisix/manager-api/test/e2enew/base"
+)
+
+// just test for schema check
+var _ = ginkgo.Describe("Upstream keepalive pool", func() {
+       ginkgo.It("create upstream with keepalive pool", func() {
+               createUpstreamBody := make(map[string]interface{})
+               createUpstreamBody["nodes"] = []map[string]interface{}{
+                       {
+                               "host":   base.UpstreamIp,
+                               "port":   1980,
+                               "weight": 1,
+                       },
+               }
+               createUpstreamBody["type"] = "roundrobin"
+               createUpstreamBody["retries"] = 5
+               createUpstreamBody["retry_timeout"] = 5.5
+               _createUpstreamBody, err := json.Marshal(createUpstreamBody)
+               gomega.Expect(err).To(gomega.BeNil())
+               base.RunTestCase(base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodPut,
+                       Path:         "/apisix/admin/upstreams/retry",
+                       Body:         string(_createUpstreamBody),
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+               })
+       })
+       ginkgo.It("delete upstream", func() {
+               base.RunTestCase(base.HttpTestCase{
+                       Object:       base.ManagerApiExpect(),
+                       Method:       http.MethodDelete,
+                       Path:         "/apisix/admin/upstreams/retry",
+                       Headers:      map[string]string{"Authorization": 
base.GetToken()},
+                       ExpectStatus: http.StatusOK,
+               })
+       })
+})
diff --git a/api/test/e2enew/upstream/upstream_test.go 
b/api/test/e2enew/upstream/upstream_test.go
index f0ff938..2689b0a 100644
--- a/api/test/e2enew/upstream/upstream_test.go
+++ b/api/test/e2enew/upstream/upstream_test.go
@@ -845,7 +845,6 @@ var _ = ginkgo.Describe("test upstream delete (route is in 
use)", func() {
                        Body: `{
                                "name": "route1",
                                "id": "r1",
-                               "name": "route1",
                                "uri": "/hello",
                                "upstream_id": "u1"
                        }`,
diff --git a/web/cypress/fixtures/export-route-dataset.json 
b/web/cypress/fixtures/export-route-dataset.json
index 2356f82..339b05e 100644
--- a/web/cypress/fixtures/export-route-dataset.json
+++ b/web/cypress/fixtures/export-route-dataset.json
@@ -40,12 +40,17 @@
             ],
             "timeout": {
               "connect": 6,
-              "read": 6,
-              "send": 6
+              "send": 6,
+              "read": 6
             },
             "type": "roundrobin",
             "scheme": "http",
-            "pass_host": "pass"
+            "pass_host": "pass",
+            "keepalive_pool": {
+              "idle_timeout": 60,
+              "requests": 1000,
+              "size": 320
+            }
           }
         }
       }
@@ -92,12 +97,17 @@
             ],
             "timeout": {
               "connect": 6,
-              "read": 6,
-              "send": 6
+              "send": 6,
+              "read": 6
             },
             "type": "roundrobin",
             "scheme": "http",
-            "pass_host": "pass"
+            "pass_host": "pass",
+            "keepalive_pool": {
+              "idle_timeout": 60,
+              "requests": 1000,
+              "size": 320
+            }
           }
         }
       },
@@ -143,12 +153,17 @@
             ],
             "timeout": {
               "connect": 6,
-              "read": 6,
-              "send": 6
+              "send": 6,
+              "read": 6
             },
             "type": "roundrobin",
             "scheme": "http",
-            "pass_host": "pass"
+            "pass_host": "pass",
+            "keepalive_pool": {
+              "idle_timeout": 60,
+              "requests": 1000,
+              "size": 320
+            }
           }
         }
       }
diff --git a/web/cypress/fixtures/plugin-dataset.json 
b/web/cypress/fixtures/plugin-dataset.json
index 940f34a..0ae63b9 100644
--- a/web/cypress/fixtures/plugin-dataset.json
+++ b/web/cypress/fixtures/plugin-dataset.json
@@ -291,12 +291,12 @@
     {
       "shouldValid": true,
       "data": {
-        "allow_origins": "",
-        "allow_methods": "",
-        "allow_headers": "",
-        "expose_headers": "",
-        "max_age": 600,
-        "allow_credential": true
+        "allow_origins": "*",
+        "allow_methods": "*",
+        "allow_headers": "*",
+        "expose_headers": "*",
+        "max_age": 5,
+        "allow_credential": false
       }
     },
     {
@@ -506,7 +506,7 @@
       }
     },
     {
-      "shouldValid": true,
+      "shouldValid": false,
       "data": {
         "conn": 5,
         "burst": 1,
@@ -516,7 +516,7 @@
       }
     },
     {
-      "shouldValid": true,
+      "shouldValid": false,
       "data": {
         "conn": 5,
         "burst": 1,
@@ -693,13 +693,13 @@
       "data": {}
     },
     {
-      "shouldValid": false,
+      "shouldValid": true,
       "data": {
         "invalid": "invalid"
       }
     },
     {
-      "shouldValid": false,
+      "shouldValid": true,
       "data": {
         "invalid_property": 1
       }
@@ -862,7 +862,7 @@
       }
     },
     {
-      "shouldValid": false,
+      "shouldValid": true,
       "data": {
         "uri": "/apisix/home",
         "host": "apisix.apache.org",
@@ -1054,7 +1054,7 @@
       }
     },
     {
-      "shouldValid": false,
+      "shouldValid": true,
       "data": {
         "body": "Hello world",
         "headers": {
diff --git 
a/web/cypress/integration/consumer/create-with-limit-conn-form.spec.js 
b/web/cypress/integration/consumer/create-with-limit-conn-form.spec.js
index b4cac1d..8eb41ae 100644
--- a/web/cypress/integration/consumer/create-with-limit-conn-form.spec.js
+++ b/web/cypress/integration/consumer/create-with-limit-conn-form.spec.js
@@ -30,6 +30,7 @@ context('Create and delete consumer with limit-conn plugin 
form', () => {
     conn: '#conn',
     burst: '#burst',
     default_conn_delay: '#default_conn_delay',
+    only_use_default_delay: '#only_use_default_delay',
     key: '#key',
     rejected_code: '#rejected_code',
     title: '[title="remote_addr"]',
@@ -89,6 +90,7 @@ context('Create and delete consumer with limit-conn plugin 
form', () => {
     cy.get(selector.conn).type(data.conn);
     cy.get(selector.burst).type(data.burst);
     cy.get(selector.default_conn_delay).type(data.default_conn_delay);
+    cy.get(selector.only_use_default_delay).click();
     cy.get(selector.key).click();
     cy.get(selector.selectDropdown).should('be.visible');
     cy.get(selector.title).click({
diff --git 
a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js 
b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
index 6798186..70a5ebc 100644
--- a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
+++ b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
@@ -246,4 +246,65 @@ context('Create and Delete Upstream', () => {
     cy.contains('button', 'Confirm').click();
     cy.get(selector.notification).should('contain', 
data.deleteUpstreamSuccess);
   });
+
+  it('should create upstream with keepalive pool default value', function () {
+    cy.visit('/');
+    cy.contains('Upstream').click();
+    cy.contains('Create').click();
+
+    cy.get(selector.name).type(data.upstreamName);
+    cy.get(selector.description).type(data.description);
+
+    cy.get(selector.nodes_0_host).type(data.ip1);
+    cy.get(selector.nodes_0_port).clear().type('7000');
+    cy.get(selector.nodes_0_weight).clear().type(1);
+
+    cy.get('#keepalive_pool_size').clear().type('1');
+    cy.get('#keepalive_pool_idle_timeout').clear().type('15.5');
+    cy.get('#keepalive_pool_requests').clear().type('50');
+
+    cy.contains('Next').click();
+    cy.get(selector.input).should('be.disabled');
+    cy.contains('Submit').click();
+    cy.get(selector.notification).should('contain', 
data.createUpstreamSuccess);
+    cy.url().should('contains', 'upstream/list');
+  });
+
+  it('should delete the upstream', function () {
+    cy.visit('/');
+    cy.contains('Upstream').click();
+    cy.contains(data.upstreamName).siblings().contains('Delete').click();
+    cy.contains('button', 'Confirm').click();
+    cy.get(selector.notification).should('contain', 
data.deleteUpstreamSuccess);
+  });
+
+  it('should create upstream with retries and retry timeout', function () {
+    cy.visit('/');
+    cy.contains('Upstream').click();
+    cy.contains('Create').click();
+
+    cy.get(selector.name).type(data.upstreamName);
+    cy.get(selector.description).type(data.description);
+
+    cy.get(selector.nodes_0_host).type(data.ip1);
+    cy.get(selector.nodes_0_port).clear().type('7000');
+    cy.get(selector.nodes_0_weight).clear().type(1);
+
+    cy.get('#retries').clear().type('5');
+    cy.get('#retry_timeout').clear().type('15.5');
+
+    cy.contains('Next').click();
+    cy.get(selector.input).should('be.disabled');
+    cy.contains('Submit').click();
+    cy.get(selector.notification).should('contain', 
data.createUpstreamSuccess);
+    cy.url().should('contains', 'upstream/list');
+  });
+
+  it('should delete the upstream', function () {
+    cy.visit('/');
+    cy.contains('Upstream').click();
+    cy.contains(data.upstreamName).siblings().contains('Delete').click();
+    cy.contains('button', 'Confirm').click();
+    cy.get(selector.notification).should('contain', 
data.deleteUpstreamSuccess);
+  });
 });
diff --git a/web/src/components/Plugin/UI/limit-conn.tsx 
b/web/src/components/Plugin/UI/limit-conn.tsx
index a680b7d..9928e6b 100644
--- a/web/src/components/Plugin/UI/limit-conn.tsx
+++ b/web/src/components/Plugin/UI/limit-conn.tsx
@@ -16,7 +16,7 @@
  */
 import React from 'react';
 import type { FormInstance } from 'antd/es/form';
-import { Form, InputNumber, Select } from 'antd';
+import { Form, InputNumber, Select, Switch } from 'antd';
 import { useIntl } from 'umi';
 
 type Props = {
@@ -37,6 +37,9 @@ const FORM_ITEM_LAYOUT = {
 const LimitConn: React.FC<Props> = ({ form, schema }) => {
   const { formatMessage } = useIntl();
   const propertires = schema?.properties;
+  const onlyUseDefaultDelay = form.getFieldValue('only_use_default_delay')
+    ? form.getFieldValue('only_use_default_delay')
+    : false;
   return (
     <Form form={form} {...FORM_ITEM_LAYOUT}>
       <Form.Item
@@ -67,6 +70,17 @@ const LimitConn: React.FC<Props> = ({ form, schema }) => {
       </Form.Item>
 
       <Form.Item
+        label="only_use_default_delay"
+        name="only_use_default_delay"
+        initialValue={propertires.only_use_default_delay.default}
+        tooltip={formatMessage({
+          id: 'component.pluginForm.limit-conn.only_use_default_delay.tooltip',
+        })}
+      >
+        <Switch defaultChecked={onlyUseDefaultDelay} />
+      </Form.Item>
+
+      <Form.Item
         label="key"
         required
         name="key"
@@ -82,19 +96,6 @@ const LimitConn: React.FC<Props> = ({ form, schema }) => {
           })}
         </Select>
       </Form.Item>
-
-      <Form.Item
-        label="rejected_code"
-        name="rejected_code"
-        initialValue={propertires.rejected_code.default}
-        tooltip={formatMessage({ id: 
'component.pluginForm.limit-conn.rejected_code.tooltip' })}
-      >
-        <InputNumber
-          min={propertires.rejected_code.minimum}
-          max={propertires.rejected_code.maximum}
-          required
-        />
-      </Form.Item>
     </Form>
   );
 };
diff --git a/web/src/components/Plugin/locales/en-US.ts 
b/web/src/components/Plugin/locales/en-US.ts
index 689a6fc..39bdb31 100644
--- a/web/src/components/Plugin/locales/en-US.ts
+++ b/web/src/components/Plugin/locales/en-US.ts
@@ -85,6 +85,8 @@ export default {
     'to limit the concurrency level. For example, one can use the host name 
(or server zone) as the key so that we limit concurrency per host name. 
Otherwise, we can also use the client address as the key so that we can avoid a 
single client from flooding our service with too many parallel connections or 
requests. Now accept those as key: "remote_addr"(client\'s IP), 
"server_addr"(server\'s IP), "X-Forwarded-For/X-Real-IP" in request header, 
"consumer_name"(consumer\'s username).',
   'component.pluginForm.limit-conn.rejected_code.tooltip':
     'returned when the request exceeds conn + burst will be rejected.',
+  'component.pluginForm.limit-conn.only_use_default_delay.tooltip':
+    'enable the strict mode of the latency seconds. If you set this option to 
true, it will run strictly according to the latency seconds you set without 
additional calculation logic.',
 
   // limit-req
   'component.pluginForm.limit-req.rate.tooltip':
diff --git a/web/src/components/Plugin/locales/zh-CN.ts 
b/web/src/components/Plugin/locales/zh-CN.ts
index f7ef721..324ae28 100644
--- a/web/src/components/Plugin/locales/zh-CN.ts
+++ b/web/src/components/Plugin/locales/zh-CN.ts
@@ -80,6 +80,9 @@ export default {
     '用户指定的限制并发级别的关键字,可以是客户端 IP 或服务端 IP。例如,可以使用主机名(或服务器区域)作为关键字,以便限制每个主机名的并发性。 
否则,我们也可以使用客户端地址作为关键字,这样我们就可以避免单个客户端用太多的并行连接或请求淹没我们的服务。当前接受的 key 
有:"remote_addr"(客户端 IP 地址), "server_addr"(服务端 IP 地址), 请求头中的"X-Forwarded-For" 或 
"X-Real-IP", "consumer_name"(consumer 的 username)。',
   'component.pluginForm.limit-conn.rejected_code.tooltip':
     '当请求超过 conn + burst 这个阈值时,返回的 HTTP 状态码。',
+  'component.pluginForm.limit-conn.only_use_default_delay.tooltip':
+    '延迟时间的严格模式。 如果设置为true的话,将会严格按照设置的时间来进行延迟',
+
   // limit-req
   'component.pluginForm.limit-req.rate.tooltip':
     '指定的请求速率(以秒为单位),请求速率超过 rate 但没有超过 (rate + brust)的请求会被加上延时。',
diff --git a/web/src/components/Upstream/UpstreamForm.tsx 
b/web/src/components/Upstream/UpstreamForm.tsx
index 3afb18b..c12898a 100644
--- a/web/src/components/Upstream/UpstreamForm.tsx
+++ b/web/src/components/Upstream/UpstreamForm.tsx
@@ -31,6 +31,8 @@ import PassHost from './components/PassHost';
 import TLSComponent from './components/TLS';
 import UpstreamType from './components/UpstreamType';
 import { convertToRequestData } from './service';
+import RetryTimeout from './components/RetryTimeout';
+import KeepalivePool from './components/KeepalivePool';
 
 type Upstream = {
   name?: string;
@@ -270,6 +272,14 @@ const UpstreamForm: React.FC<Props> = forwardRef(
       );
     };
 
+    const KeepalivePoolComponent = () => {
+      return (
+        <PanelSection title={formatMessage({ id: 
'page.upstream.step.keepalive_pool' })}>
+          <KeepalivePool readonly={readonly} />
+        </PanelSection>
+      );
+    };
+
     return (
       <Form form={form} labelCol={{ span: 3 }}>
         {showSelector && (
@@ -291,6 +301,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
 
             <PassHost form={form} readonly={readonly} />
             <Retries readonly={readonly} />
+            <RetryTimeout readonly={readonly} />
 
             <Scheme readonly={readonly} />
             <Form.Item noStyle shouldUpdate={(prev, next) => prev.scheme !== 
next.scheme}>
@@ -307,6 +318,8 @@ const UpstreamForm: React.FC<Props> = forwardRef(
               <Timeout key={index} {...item} readonly={readonly} />
             ))}
 
+            <KeepalivePoolComponent />
+
             <HealthCheckComponent />
           </React.Fragment>
         )}
diff --git a/web/src/components/Upstream/components/KeepalivePool.tsx 
b/web/src/components/Upstream/components/KeepalivePool.tsx
new file mode 100644
index 0000000..f1fcc98
--- /dev/null
+++ b/web/src/components/Upstream/components/KeepalivePool.tsx
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { Row, Col, Form, InputNumber } from 'antd';
+import { useIntl } from 'umi';
+
+type Props = {
+  readonly?: boolean;
+};
+
+const KeepalivePool: React.FC<Props> = ({ readonly }) => {
+  const { formatMessage } = useIntl();
+
+  return (
+    <React.Fragment>
+      <Form.Item
+        label={formatMessage({ id: 'component.upstream.fields.keepalive_pool' 
})}
+        tooltip={formatMessage({ id: 
'component.upstream.fields.keepalive_pool.tooltip' })}
+      >
+        <Row style={{ marginBottom: 10 }} gutter={10}>
+          <Col span={5}>
+            <Form.Item
+              name={['keepalive_pool', 'size']}
+              label={formatMessage({ id: 
'component.upstream.fields.keepalive_pool.size' })}
+              style={{ marginBottom: 0 }}
+              initialValue={320}
+            >
+              <InputNumber
+                min={1}
+                placeholder={formatMessage({
+                  id: 
'component.upstream.fields.keepalive_pool.size.placeholder',
+                })}
+                disabled={readonly}
+              />
+            </Form.Item>
+          </Col>
+          <Col span={7}>
+            <Form.Item
+              name={['keepalive_pool', 'idle_timeout']}
+              label={formatMessage({ id: 
'component.upstream.fields.keepalive_pool.idle_timeout' })}
+              style={{ marginBottom: 0 }}
+              initialValue={60}
+            >
+              <InputNumber
+                min={0}
+                placeholder={formatMessage({
+                  id: 
'component.upstream.fields.keepalive_pool.idle_timeout.placeholder',
+                })}
+                disabled={readonly}
+              />
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item
+              name={['keepalive_pool', 'requests']}
+              label={formatMessage({ id: 
'component.upstream.fields.keepalive_pool.requests' })}
+              style={{ marginBottom: 0 }}
+              initialValue={1000}
+            >
+              <InputNumber
+                min={1}
+                placeholder={formatMessage({
+                  id: 
'component.upstream.fields.keepalive_pool.requests.placeholder',
+                })}
+                disabled={readonly}
+              />
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form.Item>
+    </React.Fragment>
+  );
+};
+
+export default KeepalivePool;
diff --git a/web/src/components/Upstream/components/RetryTimeout.tsx 
b/web/src/components/Upstream/components/RetryTimeout.tsx
new file mode 100644
index 0000000..2fab431
--- /dev/null
+++ b/web/src/components/Upstream/components/RetryTimeout.tsx
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { Form, InputNumber } from 'antd';
+import { useIntl } from 'umi';
+
+type Props = {
+  readonly?: boolean;
+};
+
+const RetryTimeout: React.FC<Props> = ({ readonly }) => {
+  const { formatMessage } = useIntl();
+
+  return (
+    <React.Fragment>
+      <Form.Item
+        name="retry_timeout"
+        label={formatMessage({ id: 'component.upstream.fields.retry_timeout' 
})}
+        tooltip={formatMessage({ id: 
'component.upstream.fields.retry_timeout.tooltip' })}
+      >
+        <InputNumber disabled={readonly} />
+      </Form.Item>
+    </React.Fragment>
+  );
+};
+
+export default RetryTimeout;
diff --git a/web/src/components/Upstream/locales/en-US.ts 
b/web/src/components/Upstream/locales/en-US.ts
index c8b8b90..b449349 100644
--- a/web/src/components/Upstream/locales/en-US.ts
+++ b/web/src/components/Upstream/locales/en-US.ts
@@ -57,6 +57,20 @@ export default {
   'component.upstream.fields.retries.tooltip':
     'The retry mechanism sends the request to the next upstream node. A value 
of 0 disables the retry mechanism and leaves the table empty to use the number 
of available backend nodes.',
 
+  'component.upstream.fields.retry_timeout': 'Retry Timeout',
+  'component.upstream.fields.retry_timeout.tooltip':
+    'Configure a number to limit the amount of seconds that retries can be 
continued, and do not continue retries if the previous request and retry 
requests have taken too long. 0 means disable retry timeout mechanism.',
+
+  'component.upstream.fields.keepalive_pool': 'Keepalive Pool',
+  'component.upstream.fields.keepalive_pool.tooltip': 'Set independent 
keepalive pool for Upstream',
+  'component.upstream.fields.keepalive_pool.size': 'Size',
+  'component.upstream.fields.keepalive_pool.size.placeholder': 'Please enter 
the size',
+  'component.upstream.fields.keepalive_pool.idle_timeout': 'Idle Timeout',
+  'component.upstream.fields.keepalive_pool.idle_timeout.placeholder':
+    'Please enter the idle timeout',
+  'component.upstream.fields.keepalive_pool.requests': 'Requests',
+  'component.upstream.fields.keepalive_pool.requests.placeholder': 'Please 
enter the requests',
+
   'component.upstream.fields.checks.active.type': 'Type',
   'component.upstream.fields.checks.active.type.tooltip':
     'Whether to perform active health checks using HTTP or HTTPS, or just 
attempt a TCP connection.',
diff --git a/web/src/components/Upstream/locales/zh-CN.ts 
b/web/src/components/Upstream/locales/zh-CN.ts
index 1adb63f..4e1dc10 100644
--- a/web/src/components/Upstream/locales/zh-CN.ts
+++ b/web/src/components/Upstream/locales/zh-CN.ts
@@ -56,6 +56,19 @@ export default {
   'component.upstream.fields.retries.tooltip':
     '重试机制将请求发到下一个上游节点。值为 0 表示禁用重试机制,留空表示使用可用后端节点的数量。',
 
+  'component.upstream.fields.retry_timeout': '重试超时时间',
+  'component.upstream.fields.retry_timeout.tooltip':
+    '限制是否继续重试的时间,若之前的请求和重试请求花费太多时间就不再继续重试。0 代表不启用重试超时机制。',
+
+  'component.upstream.fields.keepalive_pool': '连接池',
+  'component.upstream.fields.keepalive_pool.tooltip': '为 upstream 对象设置独立的连接池',
+  'component.upstream.fields.keepalive_pool.size': '容量',
+  'component.upstream.fields.keepalive_pool.size.placeholder': '请输入容量',
+  'component.upstream.fields.keepalive_pool.idle_timeout': '空闲超时时间',
+  'component.upstream.fields.keepalive_pool.idle_timeout.placeholder': 
'请输入空闲超时时间',
+  'component.upstream.fields.keepalive_pool.requests': '请求数量',
+  'component.upstream.fields.keepalive_pool.requests.placeholder': '请输入请求数量',
+
   'component.upstream.fields.checks.active.type': '类型',
   'component.upstream.fields.checks.active.type.tooltip':
     '是使用 HTTP 或 HTTPS 进行主动健康检查,还是只尝试 TCP 连接。',
diff --git a/web/src/pages/Upstream/locales/en-US.ts 
b/web/src/pages/Upstream/locales/en-US.ts
index 8cbd798..424df4e 100644
--- a/web/src/pages/Upstream/locales/en-US.ts
+++ b/web/src/pages/Upstream/locales/en-US.ts
@@ -65,6 +65,7 @@ export default {
   'page.upstream.step.input.healthyCheck.passive.http_statuses': 'Please enter 
http status',
   'page.upstream.step.healthyCheck.passive.tcp_failures': 'TCP Failures',
   'page.upstream.step.input.healthyCheck.passive.tcp_failures': 'Please enter 
TCP failures',
+  'page.upstream.step.keepalive_pool': 'Keepalive Pool',
   'page.upstream.notificationMessage.enableHealthCheckFirst': 'Please enable 
health check first.',
   'page.upstream.upstream_host.required': 'Please enter the custom Host',
 
diff --git a/web/src/pages/Upstream/locales/zh-CN.ts 
b/web/src/pages/Upstream/locales/zh-CN.ts
index 2db82eb..b2d6778 100644
--- a/web/src/pages/Upstream/locales/zh-CN.ts
+++ b/web/src/pages/Upstream/locales/zh-CN.ts
@@ -64,6 +64,7 @@ export default {
   'page.upstream.step.input.healthyCheck.passive.http_statuses': '请输入状态码',
   'page.upstream.step.healthyCheck.passive.tcp_failures': 'TCP 失败次数',
   'page.upstream.step.input.healthyCheck.passive.tcp_failures': '请输入 TCP 失败次数',
+  'page.upstream.step.keepalive_pool': '连接池',
   'page.upstream.notificationMessage.enableHealthCheckFirst': '请先启用探活健康检查。',
   'page.upstream.upstream_host.required': '请输入自定义 Host 请求头',
 
diff --git a/web/src/pages/Upstream/typing.d.ts 
b/web/src/pages/Upstream/typing.d.ts
index 3a7d03e..5c73cc7 100644
--- a/web/src/pages/Upstream/typing.d.ts
+++ b/web/src/pages/Upstream/typing.d.ts
@@ -23,6 +23,12 @@ declare namespace UpstreamModule {
     namespace_id?: string;
   };
 
+  type KeepalivePool = {
+    size?: number;
+    idle_timeout?: number;
+    requests?: number;
+  };
+
   type Timeout = Record<'connect' | 'send' | 'read', number>;
 
   type HealthCheck = {
@@ -81,12 +87,14 @@ declare namespace UpstreamModule {
     key?: string;
     checks?: HealthCheck;
     retries?: number;
+    retry_timeout?: number;
     enable_websocket?: boolean;
     timeout?: Timeout;
     name?: string;
     desc?: string;
     pass_host?: 'pass' | 'node' | 'rewrite';
     upstream_host: UpstreamHost[];
+    keepalive_pool: KeepalivePool;
 
     // Custom Fields that need to be omitted
     custom?: {};

Reply via email to