From 3eac49675a2c4a55a2b08e0c2a31dbaa7ee68e5c Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Thu, 2 Sep 2021 23:51:28 +0800 Subject: [PATCH 01/18] feat: update json schema file --- api/conf/schema.json | 693 +++++++++++++++++++++++++------------------ 1 file changed, 410 insertions(+), 283 deletions(-) diff --git a/api/conf/schema.json b/api/conf/schema.json index 9b454b5bf7..5d8f90446e 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": { @@ -2601,37 +2720,10 @@ }, "version": 0.1 }, - "dubbo-proxy": { - "priority": 507, - "schema": { - "$comment": "this is a mark for our injected plugin schema", - "properties": { - "disable": { - "type": "boolean" - }, - "method": { - "minLength": 1, - "type": "string" - }, - "service_name": { - "minLength": 1, - "type": "string" - }, - "service_version": { - "pattern": "^\\d+\\.\\d+\\.\\d+", - "type": "string" - } - }, - "required": ["service_name", "service_version"], - "type": "object" - }, - "version": 0.1 - }, "echo": { "priority": 412, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "anyOf": [{ "required": ["before_body"] }, { @@ -2666,87 +2758,8 @@ }, "version": 0.1 }, - "error-log-logger": { - "metadata_schema": { - "properties": { - "batch_max_size": { - "default": 1000, - "minimum": 0, - "type": "integer" - }, - "buffer_duration": { - "default": 60, - "minimum": 1, - "type": "integer" - }, - "host": { - "pattern": "^\\*?[0-9a-zA-Z-._]+$", - "type": "string" - }, - "inactive_timeout": { - "default": 3, - "minimum": 1, - "type": "integer" - }, - "keepalive": { - "default": 30, - "minimum": 1, - "type": "integer" - }, - "level": { - "default": "WARN", - "enum": ["ALERT", "CRIT", "DEBUG", "EMERG", "ERR", "ERROR", "INFO", "NOTICE", "STDERR", "WARN"], - "type": "string" - }, - "max_retry_count": { - "default": 0, - "minimum": 0, - "type": "integer" - }, - "name": { - "default": "error-log-logger", - "type": "string" - }, - "port": { - "minimum": 0, - "type": "integer" - }, - "retry_delay": { - "default": 1, - "minimum": 0, - "type": "integer" - }, - "timeout": { - "default": 3, - "minimum": 1, - "type": "integer" - }, - "tls": { - "default": false, - "type": "boolean" - }, - "tls_server_name": { - "type": "string" - } - }, - "required": ["host", "port"], - "type": "object" - }, - "priority": 1091, - "schema": { - "$comment": "this is a mark for our injected plugin schema", - "properties": { - "disable": { - "type": "boolean" - } - }, - "type": "object" - }, - "version": 0.1 - }, "example-plugin": { "metadata_schema": { - "additionalProperties": false, "properties": { "ikey": { "minimum": 0, @@ -2976,9 +2989,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 +3100,6 @@ "priority": 2530, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "disable": { "type": "boolean" @@ -3039,7 +3113,6 @@ }, "http-logger": { "metadata_schema": { - "additionalProperties": false, "properties": { "log_format": { "default": { @@ -3121,67 +3194,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 +3314,6 @@ "priority": 2510, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "disable": { "type": "boolean" @@ -3255,6 +3325,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 +3410,6 @@ }, "key-auth": { "consumer_schema": { - "additionalProperties": false, "properties": { "key": { "type": "string" @@ -3339,7 +3421,6 @@ "priority": 2500, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "disable": { "type": "boolean" @@ -3347,6 +3428,10 @@ "header": { "default": "apikey", "type": "string" + }, + "query": { + "default": "apikey", + "type": "string" } }, "type": "object" @@ -3375,14 +3460,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 +3547,10 @@ } }, "properties": { + "allow_degradation": { + "default": false, + "type": "boolean" + }, "count": { "exclusiveMinimum": 0, "type": "integer" @@ -3487,6 +3574,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 +3597,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 +3625,10 @@ "maximum": 599, "minimum": 200, "type": "integer" + }, + "rejected_msg": { + "minLength": 1, + "type": "string" } }, "required": ["burst", "key", "rate"], @@ -3533,20 +3636,6 @@ }, "version": 0.1 }, - "log-rotate": { - "priority": 100, - "schema": { - "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, - "properties": { - "disable": { - "type": "boolean" - } - }, - "type": "object" - }, - "version": 0.1 - }, "mqtt-proxy": { "priority": 1000, "schema": { @@ -3586,20 +3675,6 @@ }, "version": 0.1 }, - "node-status": { - "priority": 1000, - "schema": { - "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, - "properties": { - "disable": { - "type": "boolean" - } - }, - "type": "object" - }, - "version": 0.1 - }, "openid-connect": { "priority": 2599, "schema": { @@ -3690,7 +3765,6 @@ "priority": 500, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "disable": { "type": "boolean" @@ -3742,8 +3816,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 +3873,6 @@ "priority": 1008, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "minProperties": 1, "properties": { "disable": { @@ -3842,6 +3915,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 +4011,6 @@ "priority": 2990, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "bypass_missing": { "default": false, @@ -3925,6 +4038,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 +4094,6 @@ "priority": 899, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "minProperties": 1, "properties": { "body": { @@ -4014,7 +4131,6 @@ "priority": 990, "schema": { "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, "properties": { "disable": { "type": "boolean" @@ -4076,49 +4192,6 @@ }, "version": 0.1 }, - "skywalking": { - "metadata_schema": { - "additionalProperties": false, - "properties": { - "endpoint_addr": { - "default": "http://127.0.0.1:12800", - "type": "string" - }, - "report_interval": { - "type": "integer" - }, - "service_instance_name": { - "default": "APISIX Instance Name", - "description": "User Service Instance Name", - "type": "string" - }, - "service_name": { - "default": "APISIX", - "description": "service name for skywalking", - "type": "string" - } - }, - "type": "object" - }, - "priority": -1100, - "schema": { - "$comment": "this is a mark for our injected plugin schema", - "additionalProperties": false, - "properties": { - "disable": { - "type": "boolean" - }, - "sample_ratio": { - "default": 1, - "maximum": 1, - "minimum": 0.00001, - "type": "number" - } - }, - "type": "object" - }, - "version": 0.1 - }, "sls-logger": { "priority": 406, "schema": { @@ -4335,14 +4408,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 +4433,6 @@ "items": { "properties": { "upstream": { - "additionalProperties": false, "oneOf": [{ "required": ["nodes", "type"] }, { @@ -4370,7 +4440,6 @@ }], "properties": { "checks": { - "additionalProperties": false, "anyOf": [{ "required": ["active"] }, { @@ -4595,6 +4664,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 +4760,10 @@ "minimum": 0, "type": "integer" }, + "retry_timeout": { + "minimum": 0, + "type": "number" + }, "scheme": { "default": "http", "enum": ["grpc", "grpcs", "http", "https"] @@ -4716,7 +4809,6 @@ }, "type": { "description": "algorithms of load balancing", - "enum": ["chash", "ewma", "least_conn", "roundrobin"], "type": "string" }, "update_time": { @@ -4763,6 +4855,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 +4956,10 @@ "default": 403, "minimum": 200, "type": "integer" + }, + "rejected_msg": { + "minLength": 1, + "type": "string" } }, "required": ["block_rules"], @@ -4903,4 +5030,4 @@ "version": 0.1 } } -} +} \ No newline at end of file From bd5d3b01ed8728acd63867321092de4f9bf3afc7 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 00:06:07 +0800 Subject: [PATCH 02/18] feat: update entity definition --- api/internal/core/entity/entity.go | 69 +++++++++++++++++------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/api/internal/core/entity/entity.go b/api/internal/core/entity/entity.go index efa10beb32..1d17c9a4ff 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 From 10f7dcd44d712e337d8824012ca589c392c92415 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 01:31:19 +0800 Subject: [PATCH 03/18] feat: add new upstream property to frontend --- 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 ++ 8 files changed, 180 insertions(+) create mode 100644 web/src/components/Upstream/components/KeepalivePool.tsx create mode 100644 web/src/components/Upstream/components/RetryTimeout.tsx diff --git a/web/src/components/Upstream/UpstreamForm.tsx b/web/src/components/Upstream/UpstreamForm.tsx index 3afb18b8f6..c12898a4b5 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 = forwardRef( ); }; + const KeepalivePoolComponent = () => { + return ( + + + + ); + }; + return (
{showSelector && ( @@ -291,6 +301,7 @@ const UpstreamForm: React.FC = forwardRef( + prev.scheme !== next.scheme}> @@ -307,6 +318,8 @@ const UpstreamForm: React.FC = forwardRef( ))} + + )} diff --git a/web/src/components/Upstream/components/KeepalivePool.tsx b/web/src/components/Upstream/components/KeepalivePool.tsx new file mode 100644 index 0000000000..f1fcc984af --- /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 = ({ readonly }) => { + const { formatMessage } = useIntl(); + + return ( + + + + + + + + + + + + + + + + + + + + + + ); +}; + +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 0000000000..2fab431dc6 --- /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 = ({ readonly }) => { + const { formatMessage } = useIntl(); + + return ( + + + + + + ); +}; + +export default RetryTimeout; diff --git a/web/src/components/Upstream/locales/en-US.ts b/web/src/components/Upstream/locales/en-US.ts index c8b8b90062..b449349768 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 1adb63fc70..4e1dc1001f 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 8cbd7988e2..424df4e832 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 2db82eb20d..b2d6778f77 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 3416354fff..b3083a171a 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?: {}; From b46d470400270d6e966163b3e23119999a0aef0f Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 02:09:08 +0800 Subject: [PATCH 04/18] fix: ci test 1 --- 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 +- 3 files changed, 3 insertions(+), 64 deletions(-) delete mode 100644 api/test/e2e/json_schema_validate_test.go 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 df467426b1..0000000000 --- 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 bb70562ee5..b482688a07 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 50a55d3881..febb3c7245 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{ From 6c7184f7be2203c5dee6462212068e44e6834f59 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 02:31:37 +0800 Subject: [PATCH 05/18] fix: unit test --- api/internal/core/store/validate_test.go | 21 +-- api/internal/handler/schema/plugin_test.go | 2 +- .../handler/upstream/upstream_test.go | 168 +++++++++--------- 3 files changed, 86 insertions(+), 105 deletions(-) diff --git a/api/internal/core/store/validate_test.go b/api/internal/core/store/validate_test.go index 7b0b6f37fc..805049975a 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 d569f2d5d2..eb61e79394 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 c2b274d4c8..47c219a4e5 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{}{ From 2278ebef3ca1bd053cf2a323c2ea7ab04045a78c Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 03:09:16 +0800 Subject: [PATCH 06/18] fix: cli test --- .github/workflows/backend-cli-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-cli-test.yml b/.github/workflows/backend-cli-test.yml index 55b42bb2ad..23234d78f8 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 }} From 86b5ba70d7225779979d51dbe3adfc28cc2c1926 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 03:15:07 +0800 Subject: [PATCH 07/18] fix: lint --- .github/workflows/go-lint.yml | 36 ----------------------------------- 1 file changed, 36 deletions(-) diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index 7f495aa5b6..c136c72020 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -12,44 +12,8 @@ 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 - if: needs.go-filter.outputs.matches == 'true' - steps: - - uses: actions/checkout@v2 - - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: latest - 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 From a9dc4c2e76ca412090dd02fc41ac67af64c503b3 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 03:28:13 +0800 Subject: [PATCH 08/18] feat: add upstream backend e2e test --- .../upstream/upstream_keepalive_pool.go | 73 +++++++++++++++++++ api/test/e2enew/upstream/upstream_retry.go | 57 +++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 api/test/e2enew/upstream/upstream_keepalive_pool.go create mode 100644 api/test/e2enew/upstream/upstream_retry.go 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 0000000000..f0026ef085 --- /dev/null +++ b/api/test/e2enew/upstream/upstream_keepalive_pool.go @@ -0,0 +1,73 @@ +/* + * 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" +) + +var nodes []map[string]interface{} = []map[string]interface{}{ + { + "host": base.UpstreamIp, + "port": 1980, + "weight": 1, + }, + { + "host": base.UpstreamIp, + "port": 1981, + "weight": 1, + }, +} + +// 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"] = nodes + 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 0000000000..c7674fbe83 --- /dev/null +++ b/api/test/e2enew/upstream/upstream_retry.go @@ -0,0 +1,57 @@ +/* + * 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"] = nodes + 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, + }) + }) +}) From e62c72244c3bb156d622a5f9006aa4342a72cc21 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 03:43:55 +0800 Subject: [PATCH 09/18] feat: add upstream frontend e2e test --- .../create_and_delete_upstream.spec.js | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) 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 dc6b8d0696..55e0fff8da 100644 --- a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js +++ b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js @@ -242,4 +242,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); + }); }); From 1246c7dfab7c2eb715ea939639706d55899d2f49 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 03:53:27 +0800 Subject: [PATCH 10/18] fix: backend e2e test --- .../upstream/upstream_keepalive_pool.go | 21 +++++++------------ api/test/e2enew/upstream/upstream_retry.go | 8 ++++++- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/api/test/e2enew/upstream/upstream_keepalive_pool.go b/api/test/e2enew/upstream/upstream_keepalive_pool.go index f0026ef085..9047ac3899 100644 --- a/api/test/e2enew/upstream/upstream_keepalive_pool.go +++ b/api/test/e2enew/upstream/upstream_keepalive_pool.go @@ -26,24 +26,17 @@ import ( "github.com/apisix/manager-api/test/e2enew/base" ) -var nodes []map[string]interface{} = []map[string]interface{}{ - { - "host": base.UpstreamIp, - "port": 1980, - "weight": 1, - }, - { - "host": base.UpstreamIp, - "port": 1981, - "weight": 1, - }, -} - // 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"] = nodes + createUpstreamBody["nodes"] = []map[string]interface{}{ + { + "host": base.UpstreamIp, + "port": 1980, + "weight": 1, + }, + } createUpstreamBody["type"] = "roundrobin" createUpstreamBody["keepalive_pool"] = map[string]interface{}{ "size": 320, diff --git a/api/test/e2enew/upstream/upstream_retry.go b/api/test/e2enew/upstream/upstream_retry.go index c7674fbe83..adb81bb4f4 100644 --- a/api/test/e2enew/upstream/upstream_retry.go +++ b/api/test/e2enew/upstream/upstream_retry.go @@ -30,7 +30,13 @@ import ( var _ = ginkgo.Describe("Upstream keepalive pool", func() { ginkgo.It("create upstream with keepalive pool", func() { createUpstreamBody := make(map[string]interface{}) - createUpstreamBody["nodes"] = nodes + createUpstreamBody["nodes"] = []map[string]interface{}{ + { + "host": base.UpstreamIp, + "port": 1980, + "weight": 1, + }, + } createUpstreamBody["type"] = "roundrobin" createUpstreamBody["retries"] = 5 createUpstreamBody["retry_timeout"] = 5.5 From 12d5cde91bee30f9beb59ec632033053a90d66ff Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Fri, 3 Sep 2021 08:02:14 +0800 Subject: [PATCH 11/18] fix: limit-conn plugin form and e2e test --- .../fixtures/export-route-dataset.json | 33 ++++++++++++++----- .../create-with-limit-conn-form.spec.js | 2 ++ 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 ++ 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/web/cypress/fixtures/export-route-dataset.json b/web/cypress/fixtures/export-route-dataset.json index 2356f828b5..339b05e582 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/integration/consumer/create-with-limit-conn-form.spec.js b/web/cypress/integration/consumer/create-with-limit-conn-form.spec.js index b4cac1d5a6..8eb41ae06d 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/src/components/Plugin/UI/limit-conn.tsx b/web/src/components/Plugin/UI/limit-conn.tsx index a680b7d8b8..9928e6b23c 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 = ({ 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, schema }) => { + + + + = ({ form, schema }) => { })} - - - - ); }; diff --git a/web/src/components/Plugin/locales/en-US.ts b/web/src/components/Plugin/locales/en-US.ts index 689a6fc3c5..39bdb31880 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 f7ef721cba..324ae28f2c 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)的请求会被加上延时。', From 159565dc5f88d1cc9f4331b6372080281520967e Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 10:16:49 +0800 Subject: [PATCH 12/18] fix: fe ci error --- web/cypress/fixtures/plugin-dataset.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/cypress/fixtures/plugin-dataset.json b/web/cypress/fixtures/plugin-dataset.json index 940f34af79..3f5bb68382 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 } }, { From 2574756bac39f628aae5357866660d48fcecb100 Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 17:09:06 +0800 Subject: [PATCH 13/18] fix: review --- .github/workflows/backend-cli-test.yml | 2 +- .github/workflows/go-lint.yml | 14 ++ api/conf/schema.json | 177 ++++++++++++++++++++++++- 3 files changed, 191 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backend-cli-test.yml b/.github/workflows/backend-cli-test.yml index 23234d78f8..8a567efab7 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.14] + etcd: [3.4.16] services: etcd: image: bitnami/etcd:${{ matrix.etcd }} diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index c136c72020..635e22d427 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -12,6 +12,20 @@ on: - 'api/**' jobs: + golangci: + runs-on: ubuntu-latest + needs: go-filter + if: needs.go-filter.outputs.matches == 'true' + steps: + - uses: actions/checkout@v2 + + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: latest + working-directory: api + args: --tests=false + only-new-issues: true gofmt: runs-on: ubuntu-latest steps: diff --git a/api/conf/schema.json b/api/conf/schema.json index 5d8f90446e..2fbbeedd7b 100644 --- a/api/conf/schema.json +++ b/api/conf/schema.json @@ -2720,6 +2720,32 @@ }, "version": 0.1 }, + "dubbo-proxy": { + "priority": 507, + "schema": { + "$comment": "this is a mark for our injected plugin schema", + "properties": { + "disable": { + "type": "boolean" + }, + "method": { + "minLength": 1, + "type": "string" + }, + "service_name": { + "minLength": 1, + "type": "string" + }, + "service_version": { + "pattern": "^\\d+\\.\\d+\\.\\d+", + "type": "string" + } + }, + "required": ["service_name", "service_version"], + "type": "object" + }, + "version": 0.1 + }, "echo": { "priority": 412, "schema": { @@ -2758,6 +2784,84 @@ }, "version": 0.1 }, + "error-log-logger": { + "metadata_schema": { + "properties": { + "batch_max_size": { + "default": 1000, + "minimum": 0, + "type": "integer" + }, + "buffer_duration": { + "default": 60, + "minimum": 1, + "type": "integer" + }, + "host": { + "pattern": "^\\*?[0-9a-zA-Z-._]+$", + "type": "string" + }, + "inactive_timeout": { + "default": 3, + "minimum": 1, + "type": "integer" + }, + "keepalive": { + "default": 30, + "minimum": 1, + "type": "integer" + }, + "level": { + "default": "WARN", + "enum": ["ALERT", "CRIT", "DEBUG", "EMERG", "ERR", "ERROR", "INFO", "NOTICE", "STDERR", "WARN"], + "type": "string" + }, + "max_retry_count": { + "default": 0, + "minimum": 0, + "type": "integer" + }, + "name": { + "default": "error-log-logger", + "type": "string" + }, + "port": { + "minimum": 0, + "type": "integer" + }, + "retry_delay": { + "default": 1, + "minimum": 0, + "type": "integer" + }, + "timeout": { + "default": 3, + "minimum": 1, + "type": "integer" + }, + "tls": { + "default": false, + "type": "boolean" + }, + "tls_server_name": { + "type": "string" + } + }, + "required": ["host", "port"], + "type": "object" + }, + "priority": 1091, + "schema": { + "$comment": "this is a mark for our injected plugin schema", + "properties": { + "disable": { + "type": "boolean" + } + }, + "type": "object" + }, + "version": 0.1 + }, "example-plugin": { "metadata_schema": { "properties": { @@ -3636,6 +3740,20 @@ }, "version": 0.1 }, + "log-rotate": { + "priority": 100, + "schema": { + "$comment": "this is a mark for our injected plugin schema", + "additionalProperties": false, + "properties": { + "disable": { + "type": "boolean" + } + }, + "type": "object" + }, + "version": 0.1 + }, "mqtt-proxy": { "priority": 1000, "schema": { @@ -3675,6 +3793,20 @@ }, "version": 0.1 }, + "node-status": { + "priority": 1000, + "schema": { + "$comment": "this is a mark for our injected plugin schema", + "additionalProperties": false, + "properties": { + "disable": { + "type": "boolean" + } + }, + "type": "object" + }, + "version": 0.1 + }, "openid-connect": { "priority": 2599, "schema": { @@ -4192,6 +4324,49 @@ }, "version": 0.1 }, + "skywalking": { + "metadata_schema": { + "additionalProperties": false, + "properties": { + "endpoint_addr": { + "default": "http://127.0.0.1:12800", + "type": "string" + }, + "report_interval": { + "type": "integer" + }, + "service_instance_name": { + "default": "APISIX Instance Name", + "description": "User Service Instance Name", + "type": "string" + }, + "service_name": { + "default": "APISIX", + "description": "service name for skywalking", + "type": "string" + } + }, + "type": "object" + }, + "priority": -1100, + "schema": { + "$comment": "this is a mark for our injected plugin schema", + "additionalProperties": false, + "properties": { + "disable": { + "type": "boolean" + }, + "sample_ratio": { + "default": 1, + "maximum": 1, + "minimum": 0.00001, + "type": "number" + } + }, + "type": "object" + }, + "version": 0.1 + }, "sls-logger": { "priority": 406, "schema": { @@ -5030,4 +5205,4 @@ "version": 0.1 } } -} \ No newline at end of file +} From 76d73b9455a2e91677b6538ef2799f819b46614e Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 17:34:01 +0800 Subject: [PATCH 14/18] fix: etcd 3.4.13 --- .github/workflows/backend-cli-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-cli-test.yml b/.github/workflows/backend-cli-test.yml index 8a567efab7..55b42bb2ad 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.16] + etcd: [3.4.13] services: etcd: image: bitnami/etcd:${{ matrix.etcd }} From bfc97caf64ee5fb10708eaf64a3311ded06e930b Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 18:43:24 +0800 Subject: [PATCH 15/18] fix: run test with apisix2.9 --- api/test/docker/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/test/docker/docker-compose.yaml b/api/test/docker/docker-compose.yaml index 3f85c51cf6..072f312045 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 From 6d5b36ffc925e1a42f8568b4546023a836e30799 Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 19:06:53 +0800 Subject: [PATCH 16/18] fix: ci --- .github/workflows/backend-cli-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backend-cli-test.yml b/.github/workflows/backend-cli-test.yml index 55b42bb2ad..23234d78f8 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 }} From 4dc4c9aa9e03c63563b2d1dbd3cb41a30bd10396 Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 19:36:42 +0800 Subject: [PATCH 17/18] fix: ci --- api/test/e2enew/upstream/upstream_test.go | 1 - web/cypress/fixtures/plugin-dataset.json | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/api/test/e2enew/upstream/upstream_test.go b/api/test/e2enew/upstream/upstream_test.go index f0ff9383a4..2689b0a679 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/plugin-dataset.json b/web/cypress/fixtures/plugin-dataset.json index 3f5bb68382..43c89d1067 100644 --- a/web/cypress/fixtures/plugin-dataset.json +++ b/web/cypress/fixtures/plugin-dataset.json @@ -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, From 5e26fc452a87332c3901989008e948f0320a9811 Mon Sep 17 00:00:00 2001 From: liuxiran Date: Fri, 3 Sep 2021 20:44:07 +0800 Subject: [PATCH 18/18] fix: ci --- web/cypress/fixtures/plugin-dataset.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/cypress/fixtures/plugin-dataset.json b/web/cypress/fixtures/plugin-dataset.json index 43c89d1067..0ae63b98e3 100644 --- a/web/cypress/fixtures/plugin-dataset.json +++ b/web/cypress/fixtures/plugin-dataset.json @@ -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": {