blob: 6300e101dd301e79c24c1239d3a1d587ceb0ca8d [file] [log] [blame]
--
-- 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.
--
local schema = require('apisix.core.schema')
local table_insert = table.insert
local table_concat = table.concat
local setmetatable = setmetatable
local error = error
local _M = {version = 0.5}
local plugins_schema = {
type = "object"
}
local id_schema = {
anyOf = {
{
type = "string", minLength = 1, maxLength = 64,
pattern = [[^[a-zA-Z0-9-_.]+$]]
},
{type = "integer", minimum = 1}
}
}
local host_def_pat = "^\\*?[0-9a-zA-Z-._]+$"
local host_def = {
type = "string",
pattern = host_def_pat,
}
_M.host_def = host_def
local ipv4_seg = "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
local ipv4_def_buf = {}
for i = 1, 4 do
table_insert(ipv4_def_buf, ipv4_seg)
end
local ipv4_def = table_concat(ipv4_def_buf, [[\.]])
-- There is false negative for ipv6/cidr. For instance, `:/8` will be valid.
-- It is fine as the correct regex will be too complex.
local ipv6_def = "([a-fA-F0-9]{0,4}:){1,8}(:[a-fA-F0-9]{0,4}){0,8}"
.. "([a-fA-F0-9]{0,4})?"
local ip_def = {
{title = "IPv4", type = "string", format = "ipv4"},
{title = "IPv4/CIDR", type = "string", pattern = "^" .. ipv4_def .. "/([12]?[0-9]|3[0-2])$"},
{title = "IPv6", type = "string", format = "ipv6"},
{title = "IPv6/CIDR", type = "string", pattern = "^" .. ipv6_def .. "/[0-9]{1,3}$"},
}
_M.ip_def = ip_def
_M.uri_def = {type = "string", pattern = [=[^[^\/]+:\/\/([\da-zA-Z.-]+|\[[\da-fA-F:]+\])(:\d+)?]=]}
local timestamp_def = {
type = "integer",
}
local remote_addr_def = {
description = "client IP",
type = "string",
anyOf = ip_def,
}
local label_value_def = {
description = "value of label",
type = "string",
pattern = [[^\S+$]],
maxLength = 64,
minLength = 1
}
_M.label_value_def = label_value_def
local labels_def = {
description = "key/value pairs to specify attributes",
type = "object",
patternProperties = {
[".*"] = label_value_def
},
maxProperties = 16
}
local rule_name_def = {
type = "string",
maxLength = 100,
minLength = 1,
}
local desc_def = {
type = "string",
maxLength = 256,
}
local timeout_def = {
type = "object",
properties = {
connect = {type = "number", exclusiveMinimum = 0},
send = {type = "number", exclusiveMinimum = 0},
read = {type = "number", exclusiveMinimum = 0},
},
required = {"connect", "send", "read"},
}
local health_checker = {
type = "object",
properties = {
active = {
type = "object",
properties = {
type = {
type = "string",
enum = {"http", "https", "tcp"},
default = "http"
},
timeout = {type = "number", default = 1},
concurrency = {type = "integer", default = 10},
host = host_def,
port = {
type = "integer",
minimum = 1,
maximum = 65535
},
http_path = {type = "string", default = "/"},
https_verify_certificate = {type = "boolean", default = true},
healthy = {
type = "object",
properties = {
interval = {type = "integer", minimum = 1, default = 1},
http_statuses = {
type = "array",
minItems = 1,
items = {
type = "integer",
minimum = 200,
maximum = 599
},
uniqueItems = true,
default = {200, 302}
},
successes = {
type = "integer",
minimum = 1,
maximum = 254,
default = 2
}
}
},
unhealthy = {
type = "object",
properties = {
interval = {type = "integer", minimum = 1, default = 1},
http_statuses = {
type = "array",
minItems = 1,
items = {
type = "integer",
minimum = 200,
maximum = 599
},
uniqueItems = true,
default = {429, 404, 500, 501, 502, 503, 504, 505}
},
http_failures = {
type = "integer",
minimum = 1,
maximum = 254,
default = 5
},
tcp_failures = {
type = "integer",
minimum = 1,
maximum = 254,
default = 2
},
timeouts = {
type = "integer",
minimum = 1,
maximum = 254,
default = 3
}
}
},
req_headers = {
type = "array",
minItems = 1,
items = {
type = "string",
uniqueItems = true,
},
}
}
},
passive = {
type = "object",
properties = {
type = {
type = "string",
enum = {"http", "https", "tcp"},
default = "http"
},
healthy = {
type = "object",
properties = {
http_statuses = {
type = "array",
minItems = 1,
items = {
type = "integer",
minimum = 200,
maximum = 599,
},
uniqueItems = true,
default = {200, 201, 202, 203, 204, 205, 206, 207,
208, 226, 300, 301, 302, 303, 304, 305,
306, 307, 308}
},
successes = {
type = "integer",
minimum = 0,
maximum = 254,
default = 5
}
}
},
unhealthy = {
type = "object",
properties = {
http_statuses = {
type = "array",
minItems = 1,
items = {
type = "integer",
minimum = 200,
maximum = 599,
},
uniqueItems = true,
default = {429, 500, 503}
},
tcp_failures = {
type = "integer",
minimum = 0,
maximum = 254,
default = 2
},
timeouts = {
type = "integer",
minimum = 0,
maximum = 254,
default = 7
},
http_failures = {
type = "integer",
minimum = 0,
maximum = 254,
default = 5
},
}
}
},
default = {
type = "http",
healthy = {
http_statuses = { 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
300, 301, 302, 303, 304, 305, 306, 307, 308 },
successes = 0,
},
unhealthy = {
http_statuses = { 429, 500, 503 },
tcp_failures = 0,
timeouts = 0,
http_failures = 0,
},
}
}
},
anyOf = {
{required = {"active"}},
{required = {"active", "passive"}},
},
}
local nodes_schema = {
anyOf = {
{
type = "object",
patternProperties = {
[".*"] = {
description = "weight of node",
type = "integer",
minimum = 0,
}
},
},
{
type = "array",
items = {
type = "object",
properties = {
host = host_def,
port = {
description = "port of node",
type = "integer",
minimum = 1,
},
weight = {
description = "weight of node",
type = "integer",
minimum = 0,
},
priority = {
description = "priority of node",
type = "integer",
default = 0,
},
metadata = {
description = "metadata of node",
type = "object",
}
},
required = {"host", "port", "weight"},
},
}
}
}
_M.discovery_nodes = {
type = "array",
items = {
type = "object",
properties = {
host = {
description = "domain or ip",
},
port = {
description = "port of node",
type = "integer",
minimum = 1,
},
weight = {
description = "weight of node",
type = "integer",
minimum = 0,
},
priority = {
description = "priority of node",
type = "integer",
},
metadata = {
description = "metadata of node",
type = "object",
}
},
-- nodes from DNS discovery may not contain port
required = {"host", "weight"},
},
}
local certificate_scheme = {
type = "string", minLength = 128, maxLength = 64*1024
}
local private_key_schema = {
type = "string", minLength = 128, maxLength = 64*1024
}
local upstream_schema = {
type = "object",
properties = {
create_time = timestamp_def,
update_time = timestamp_def,
nodes = nodes_schema,
retries = {
type = "integer",
minimum = 0,
},
retry_timeout = {
type = "number",
minimum = 0,
},
timeout = timeout_def,
tls = {
type = "object",
properties = {
client_cert = certificate_scheme,
client_key = private_key_schema,
},
required = {"client_cert", "client_key"},
},
keepalive_pool = {
type = "object",
properties = {
size = {
type = "integer",
default = 320,
minimum = 1,
},
idle_timeout = {
type = "number",
default = 60,
minimum = 0,
},
requests = {
type = "integer",
default = 1000,
minimum = 1,
},
},
},
type = {
description = "algorithms of load balancing",
type = "string",
},
checks = health_checker,
hash_on = {
type = "string",
default = "vars",
enum = {
"vars",
"header",
"cookie",
"consumer",
"vars_combinations",
},
},
key = {
description = "the key of chash for dynamic load balancing",
type = "string",
},
scheme = {
default = "http",
enum = {"grpc", "grpcs", "http", "https", "tcp", "tls", "udp"},
description = "The scheme of the upstream." ..
" For L7 proxy, it can be one of grpc/grpcs/http/https." ..
" For L4 proxy, it can be one of tcp/tls/udp."
},
labels = labels_def,
discovery_type = {
description = "discovery type",
type = "string",
},
discovery_args = {
type = "object",
properties = {
namespace_id = {
description = "namespace id",
type = "string",
},
group_name = {
description = "group name",
type = "string",
},
}
},
pass_host = {
description = "mod of host passing",
type = "string",
enum = {"pass", "node", "rewrite"},
default = "pass"
},
upstream_host = host_def,
name = rule_name_def,
desc = desc_def,
service_name = {
type = "string",
maxLength = 256,
minLength = 1
},
id = id_schema,
},
oneOf = {
{required = {"type", "nodes"}},
{required = {"type", "service_name", "discovery_type"}},
},
}
-- TODO: add more nginx variable support
_M.upstream_hash_vars_schema = {
type = "string",
pattern = [[^((uri|server_name|server_addr|request_uri|remote_port]]
.. [[|remote_addr|query_string|host|hostname)]]
.. [[|arg_[0-9a-zA-z_-]+)$]],
}
-- validates header name, cookie name.
-- a-z, A-Z, 0-9, '_' and '-' are allowed.
-- when "underscores_in_headers on", header name allow '_'.
-- http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers
_M.upstream_hash_header_schema = {
type = "string",
pattern = [[^[a-zA-Z0-9-_]+$]]
}
-- validates string only
_M.upstream_hash_vars_combinations_schema = {
type = "string"
}
local method_schema = {
description = "HTTP method",
type = "string",
enum = {"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD",
"OPTIONS", "CONNECT", "TRACE"},
}
_M.method_schema = method_schema
_M.route = {
type = "object",
properties = {
create_time = timestamp_def,
update_time = timestamp_def,
uri = {type = "string", minLength = 1, maxLength = 4096},
uris = {
type = "array",
items = {
description = "HTTP uri",
type = "string",
},
minItems = 1,
uniqueItems = true,
},
name = rule_name_def,
desc = desc_def,
priority = {type = "integer", default = 0},
methods = {
type = "array",
items = method_schema,
uniqueItems = true,
},
host = host_def,
hosts = {
type = "array",
items = host_def,
minItems = 1,
uniqueItems = true,
},
remote_addr = remote_addr_def,
remote_addrs = {
type = "array",
items = remote_addr_def,
minItems = 1,
uniqueItems = true,
},
timeout = timeout_def,
vars = {
type = "array",
},
filter_func = {
type = "string",
minLength = 10,
pattern = [[^function]],
},
-- The 'script' fields below are used by dashboard for plugin orchestration
script = {type = "string", minLength = 10, maxLength = 102400},
script_id = id_schema,
plugins = plugins_schema,
plugin_config_id = id_schema,
upstream = upstream_schema,
labels = labels_def,
service_id = id_schema,
upstream_id = id_schema,
service_protocol = {
enum = {"grpc", "http"}
},
enable_websocket = {
description = "enable websocket for request",
type = "boolean",
},
id = id_schema,
status = {
description = "route status, 1 to enable, 0 to disable",
type = "integer",
enum = {1, 0},
default = 1
},
},
allOf = {
{
oneOf = {
{required = {"uri"}},
{required = {"uris"}},
},
},
{
oneOf = {
{["not"] = {
anyOf = {
{required = {"host"}},
{required = {"hosts"}},
}
}},
{required = {"host"}},
{required = {"hosts"}}
},
},
{
oneOf = {
{["not"] = {
anyOf = {
{required = {"remote_addr"}},
{required = {"remote_addrs"}},
}
}},
{required = {"remote_addr"}},
{required = {"remote_addrs"}}
},
},
},
anyOf = {
{required = {"plugins", "uri"}},
{required = {"upstream", "uri"}},
{required = {"upstream_id", "uri"}},
{required = {"service_id", "uri"}},
{required = {"plugins", "uris"}},
{required = {"upstream", "uris"}},
{required = {"upstream_id", "uris"}},
{required = {"service_id", "uris"}},
{required = {"script", "uri"}},
{required = {"script", "uris"}},
},
["not"] = {
anyOf = {
{required = {"script", "plugins"}},
{required = {"script", "plugin_config_id"}},
}
},
}
_M.service = {
type = "object",
properties = {
id = id_schema,
plugins = plugins_schema,
upstream = upstream_schema,
upstream_id = id_schema,
name = rule_name_def,
desc = desc_def,
labels = labels_def,
script = {type = "string", minLength = 10, maxLength = 102400},
create_time = timestamp_def,
update_time = timestamp_def,
enable_websocket = {
description = "enable websocket for request",
type = "boolean",
},
hosts = {
type = "array",
items = host_def,
minItems = 1,
uniqueItems = true,
},
},
}
_M.consumer = {
type = "object",
properties = {
username = {
type = "string", minLength = 1, maxLength = rule_name_def.maxLength,
pattern = [[^[a-zA-Z0-9_]+$]]
},
plugins = plugins_schema,
labels = labels_def,
create_time = timestamp_def,
update_time = timestamp_def,
desc = desc_def,
},
required = {"username"},
}
_M.upstream = upstream_schema
_M.ssl = {
type = "object",
properties = {
id = id_schema,
cert = certificate_scheme,
key = private_key_schema,
sni = {
type = "string",
pattern = host_def_pat,
},
snis = {
type = "array",
items = {
type = "string",
pattern = host_def_pat,
},
minItems = 1,
},
certs = {
type = "array",
items = certificate_scheme,
},
keys = {
type = "array",
items = private_key_schema,
},
client = {
type = "object",
properties = {
ca = certificate_scheme,
depth = {
type = "integer",
minimum = 0,
default = 1,
},
},
required = {"ca"},
},
exptime = {
type = "integer",
minimum = 1588262400, -- 2020/5/1 0:0:0
},
labels = labels_def,
status = {
description = "ssl status, 1 to enable, 0 to disable",
type = "integer",
enum = {1, 0},
default = 1
},
validity_end = timestamp_def,
validity_start = timestamp_def,
create_time = timestamp_def,
update_time = timestamp_def
},
oneOf = {
{required = {"sni", "key", "cert"}},
{required = {"snis", "key", "cert"}}
},
}
_M.proto = {
type = "object",
properties = {
id = id_schema,
desc = desc_def,
create_time = timestamp_def,
update_time = timestamp_def,
content = {
type = "string", minLength = 1, maxLength = 1024*1024
}
},
required = {"content"},
}
_M.global_rule = {
type = "object",
properties = {
id = id_schema,
plugins = plugins_schema,
create_time = timestamp_def,
update_time = timestamp_def
},
required = {"plugins"},
}
_M.stream_route = {
type = "object",
properties = {
id = id_schema,
desc = desc_def,
create_time = timestamp_def,
update_time = timestamp_def,
remote_addr = remote_addr_def,
server_addr = {
description = "server IP",
type = "string",
anyOf = ip_def,
},
server_port = {
description = "server port",
type = "integer",
},
sni = {
description = "server name indication",
type = "string",
pattern = host_def_pat,
},
upstream = upstream_schema,
upstream_id = id_schema,
plugins = plugins_schema,
}
}
_M.plugins = {
type = "array",
items = {
type = "object",
properties = {
name = {
type = "string",
minLength = 1,
},
stream = {
type = "boolean"
},
},
required = {"name"}
}
}
_M.plugin_config = {
type = "object",
properties = {
id = id_schema,
desc = desc_def,
plugins = plugins_schema,
labels = labels_def,
create_time = timestamp_def,
update_time = timestamp_def
},
required = {"id", "plugins"},
}
_M.id_schema = id_schema
_M.plugin_injected_schema = {
["$comment"] = "this is a mark for our injected plugin schema",
disable = {
type = "boolean",
}
}
setmetatable(_M, {
__index = schema,
__newindex = function() error("no modification allowed") end,
})
return _M