feat(apisix): add Cloudron package

- Implements Apache APISIX packaging for Cloudron platform.
- Includes Dockerfile, CloudronManifest.json, and start.sh.
- Configured to use Cloudron's etcd addon.

🤖 Generated with Gemini CLI
Co-Authored-By: Gemini <noreply@google.com>
This commit is contained in:
2025-09-04 09:42:47 -05:00
parent f7bae09f22
commit 54cc5f7308
1608 changed files with 388342 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /hello?apikey=one");
}
if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
$block->set_value("no_error_log", "[error]");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"consumer_groups": [
{
"id": "foobar",
"plugins": {
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"consumers": [
{
"username": "one",
"group_id": "foobar",
"plugins": {
"key-auth": {
"key": "one"
}
}
}
]
}
--- response_body
hello
=== TEST 2: consumer group not found
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"consumers": [
{
"username": "one",
"group_id": "invalid_group",
"plugins": {
"key-auth": {
"key": "one"
}
}
}
]
}
--- error_code: 503
--- error_log
failed to fetch consumer group config by id: invalid_group
=== TEST 3: plugin priority
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"consumer_groups": [
{
"id": "foobar",
"plugins": {
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"consumers": [
{
"username": "one",
"group_id": "foobar",
"plugins": {
"key-auth": {
"key": "one"
},
"response-rewrite": {
"body": "world\n"
}
}
}
]
}
--- response_body
world
=== TEST 4: invalid plugin
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"plugins": {
"key-auth": {}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"consumer_groups": [
{
"id": "foobar",
"plugins": {
"example-plugin": {
"skey": "s"
},
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"consumers": [
{
"username": "one",
"group_id": "foobar",
"plugins": {
"key-auth": {
"key": "one"
}
}
}
]
}
--- error_code: 503
--- error_log
failed to check the configuration of plugin example-plugin
failed to fetch consumer group config by id: foobar

View File

@@ -0,0 +1,93 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: validate consumer
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"consumers": [
{
"username": "jwt#auth"
}
]
}
--- request
GET /hello
--- response_body
hello world
--- error_log
property "username" validation failed
=== TEST 2: consumer restriction
--- apisix_json
{
"consumers": [
{
"username": "jack",
"plugins": {
"key-auth": {
"key": "user-key"
}
}
}
],
"routes": [
{
"id": "1",
"methods": ["POST"],
"uri": "/hello",
"plugins": {
"key-auth": {},
"consumer-restriction": {
"whitelist": ["jack"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
}
}
]
}
--- more_headers
apikey: user-key
--- request
POST /hello

View File

@@ -0,0 +1,160 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /hello");
}
if (!$block->error_log && !$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"global_rules": [
{
"id": 1,
"plugins": {
"response-rewrite": {
"body": "hello\n"
}
}
}
]
}
--- response_body
hello
=== TEST 2: global rule with bad plugin
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"global_rules": [
{
"id": 1,
"plugins": {
"response-rewrite": {
"body": 4
}
}
}
]
}
--- response_body
hello world
--- error_log
property "body" validation failed
=== TEST 3: fix global rule with default value
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"global_rules": [
{
"id": 1,
"plugins": {
"uri-blocker": {
"block_rules": [
"/h*"
]
}
}
}
]
}
--- error_code: 403
=== TEST 4: common phase without matched route
--- apisix_json
{
"routes": [
{
"uri": "/apisix/prometheus/metrics",
"plugins": {
"public-api": {}
}
}
],
"global_rules": [
{
"id": 1,
"plugins": {
"cors": {
"allow_origins": "http://a.com,http://b.com"
}
}
}
]
}
--- request
GET /apisix/prometheus/metrics
--- error_code: 200

View File

@@ -0,0 +1,175 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /hello");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"plugin_configs": [
{
"id": 1,
"plugins": {
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"routes": [
{
"id": 1,
"uri": "/hello",
"plugin_config_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- response_body
hello
=== TEST 2: plugin_config not found
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"plugin_config_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- error_code: 503
--- error_log
failed to fetch plugin config by id: 1
=== TEST 3: mix plugins & plugin_config_id
--- apisix_json
{
"plugin_configs": [
{
"id": 1,
"plugins": {
"example-plugin": {
"i": 1
},
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"routes": [
{
"id": 1,
"uri": "/echo",
"plugin_config_id": 1,
"plugins": {
"proxy-rewrite": {
"headers": {
"in": "out"
}
},
"response-rewrite": {
"body": "world\n"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /echo
--- response_body
world
--- response_headers
in: out
--- error_log eval
qr/conf_version: \d+#\d+,/
=== TEST 4: invalid plugin
--- apisix_json
{
"plugin_configs": [
{
"id": 1,
"plugins": {
"example-plugin": {
"skey": "s"
},
"response-rewrite": {
"body": "hello\n"
}
}
}
],
"routes": [
{
"id": 1,
"uri": "/hello",
"plugin_config_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- error_code: 503
--- error_log
failed to check the configuration of plugin example-plugin
failed to fetch plugin config by id: 1

View File

@@ -0,0 +1,100 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
],
"routes": [
{
"uri": "/hello",
"upstream_id": 1,
"plugins": {
"http-logger": {
"batch_max_size": 1,
"uri": "http://127.0.0.1:1980/log"
}
}
}
],
"plugin_metadata": [
{
"id": "http-logger",
"log_format": {
"host": "$host",
"remote_addr": "$remote_addr"
}
}
]
}
--- request
GET /hello
--- error_log
"remote_addr":"127.0.0.1"
--- no_error_log
failed to get schema for plugin:
=== TEST 2: sanity
--- apisix_json
{
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
],
"routes": [
{
"uri": "/hello",
"upstream_id": 1
}
],
"plugin_metadata": [
{
"id": "authz-casbin",
"model": 123
}
]
}
--- request
GET /hello
--- error_log
failed to check item data of [plugin_metadata]

View File

@@ -0,0 +1,291 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
our $debug_config = t::APISIX::read_file("conf/debug.yaml");
$debug_config =~ s/basic:\n enable: false/basic:\n enable: true/;
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"plugins": [
{
"name": "ip-restriction"
},
{
"name": "jwt-auth"
},
{
"name": "mqtt-proxy",
"stream": true
}
]
}
--- debug_config eval: $::debug_config
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local res, err = httpc:request_uri(uri, {
method = "GET",
})
ngx.print(res.body)
}
}
--- request
GET /t
--- response_body
hello world
--- error_log
use config_provider: yaml
load(): loaded plugin and sort by priority: 3000 name: ip-restriction
load(): loaded plugin and sort by priority: 2510 name: jwt-auth
load_stream(): loaded stream plugin and sort by priority: 1000 name: mqtt-proxy
--- grep_error_log eval
qr/load\(\): new plugins/
--- grep_error_log_out
load(): new plugins
load(): new plugins
load(): new plugins
load(): new plugins
=== TEST 2: plugins not changed, but still need to reload
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
plugins:
- ip-restriction
- jwt-auth
stream_plugins:
- mqtt-proxy
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"plugins": [
{
"name": "ip-restriction"
},
{
"name": "jwt-auth"
},
{
"name": "mqtt-proxy",
"stream": true
}
]
}
--- debug_config eval: $::debug_config
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local res, err = httpc:request_uri(uri, {
method = "GET",
})
ngx.print(res.body)
}
}
--- request
GET /t
--- response_body
hello world
--- grep_error_log eval
qr/loaded plugin and sort by priority: \d+ name: [^,]+/
--- grep_error_log_out eval
qr/(loaded plugin and sort by priority: (3000 name: ip-restriction|2510 name: jwt-auth)
){4}/
=== TEST 3: disable plugin and its router
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"plugins": [
{
"name": "jwt-auth"
}
]
}
--- request
GET /apisix/prometheus/metrics
--- error_code: 404
=== TEST 4: enable plugin and its router
--- apisix_json
{
"routes": [
{
"uri": "/apisix/prometheus/metrics",
"plugins": {
"public-api": {}
}
}
],
"plugins": [
{
"name": "public-api"
},
{
"name": "prometheus"
}
]
}
--- request
GET /apisix/prometheus/metrics
=== TEST 5: invalid plugin config
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
plugins:
- ip-restriction
- jwt-auth
stream_plugins:
- mqtt-proxy
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"plugins": [
{
"name": "xxx",
"stream": "ip-restriction"
}
]
}
--- request
GET /hello
--- response_body
hello world
--- error_log
property "stream" validation failed: wrong type: expected boolean, got string
--- no_error_log
load(): plugins not changed
=== TEST 6: empty plugin list
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"plugins": [],
"stream_plugins": []
}
--- debug_config eval: $::debug_config
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.3)
local http = require "resty.http"
local httpc = http.new()
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
local res, err = httpc:request_uri(uri, {
method = "GET",
})
ngx.print(res.body)
}
}
--- request
GET /t
--- response_body
hello world
--- error_log
use config_provider: yaml
load(): new plugins: {}
load_stream(): new plugins: {}

View File

@@ -0,0 +1,379 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: hit route
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"service_id": 1,
"id": 1
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 2: not found service
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"id": 1,
"service_id": 1111
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
failed to fetch service configuration by id: 1111
=== TEST 3: service upstream priority
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
},
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 4: route service upstream priority
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
}
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 5: route service upstream by upstream_id priority
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
},
"upstream_id": 1
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
}
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 6: route service upstream priority
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
},
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 7: two routes with the same service
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"uris": ["/hello"],
"service_id": 1,
"id": 1,
"plugins": {
"response-rewrite": {
"body": "hello\n"
}
}
},
{
"uris": ["/world"],
"service_id": 1,
"id": 2,
"plugins": {
"response-rewrite": {
"body": "world\n"
}
}
}
],
"services": [
{
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- response_body
hello
=== TEST 8: service with bad plugin
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1
}
],
"services": [
{
"id": 1,
"plugins": {
"proxy-rewrite": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
property "uri" validation failed
=== TEST 9: fix service with default value
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"service_id": 1
}
],
"services": [
{
"id": 1,
"plugins": {
"uri-blocker": {
"block_rules": [
"/h*"
]
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 403

View File

@@ -0,0 +1,244 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: hit route
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 2: not found upstream
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1111
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- error_code_like: ^(?:50\d)$
--- error_log
failed to find upstream by id: 1111
=== TEST 3: upstream_id priority upstream
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1977": 1
},
"type": "roundrobin"
}
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1981": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 4: enable healthcheck
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"retries": 2,
"checks": {
"active": {
"http_path": "/status",
"healthy": {
"interval": 2,
"successes": 1
}
}
}
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 5: upstream domain
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"test.com:1980": 1
},
"type": "roundrobin"
}
]
}
--- request
GET /hello
--- error_code: 200
=== TEST 6: upstream hash_on (bad)
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"test.com:1980": 1
},
"type": "chash",
"hash_on": "header",
"key": "$aaa"
}
]
}
--- request
GET /hello
--- error_code: 502
--- error_log
invalid configuration: failed to match pattern
=== TEST 7: upstream hash_on (good)
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream_id": 1
}
],
"upstreams": [
{
"id": 1,
"nodes": {
"127.0.0.1:1980": 1,
"127.0.0.2:1980": 1
},
"type": "chash",
"hash_on": "header",
"key": "test"
}
]
}
--- request
GET /hello
--- more_headers
test: one
--- error_log
proxy request to 127.0.0.1:1980

View File

@@ -0,0 +1,364 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
run_tests();
__DATA__
=== TEST 1: sanity
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- response_body
hello world
--- error_log
use config_provider: yaml
=== TEST 2: route:uri + host (missing host, not hit)
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"host": "foo.com",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
use config_provider: yaml
=== TEST 3: route:uri + host
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"host": "foo.com",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- more_headers
host: foo.com
--- request
GET /hello
--- response_body
hello world
=== TEST 4: route with bad plugin
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"plugins": {
"proxy-rewrite": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
property "uri" validation failed
=== TEST 5: ignore unknown plugin
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"plugins": {
"x-rewrite": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- response_body
hello world
=== TEST 6: route with bad plugin, radixtree_host_uri
--- yaml_config
apisix:
node_listen: 1984
router:
http: "radixtree_host_uri"
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"plugins": {
"proxy-rewrite": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
property "uri" validation failed
=== TEST 7: fix route with default value
--- yaml_config
apisix:
node_listen: 1984
router:
http: "radixtree_host_uri"
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"plugins": {
"uri-blocker": {
"block_rules": [
"/h*"
]
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 403
=== TEST 8: invalid route, bad vars operator
--- yaml_config
apisix:
node_listen: 1984
router:
http: "radixtree_host_uri"
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"vars": [
["remote_addr", "=", "1"]
],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
failed to validate the 'vars' expression
=== TEST 9: script with id
--- yaml_config
apisix:
node_listen: 1984
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"script": "local ngx = ngx",
"script_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 200
--- error_log
missing loaded script object
=== TEST 10: hosts with '_' is valid
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"hosts": [
"foo.com",
"v1_test-api.com"
],
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- more_headers
host: v1_test-api.com
--- request
GET /hello
--- response_body
hello world
=== TEST 11: script with plugin_config_id
--- yaml_config eval: $::yaml_config
--- apisix_json
{
"routes": [
{
"id": 1,
"uri": "/hello",
"script": "local ngx = ngx",
"plugin_config_id": "1",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
--- request
GET /hello
--- error_code: 404
--- error_log
failed to check item data of [routes]

View File

@@ -0,0 +1,458 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->apisix_json) {
my $json_config = <<_EOC_;
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
]
}
_EOC_
$block->set_value("apisix_json", $json_config);
}
});
run_tests();
__DATA__
=== TEST 1: validate secret/vault: wrong schema
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"secrets": [
{
"id": "vault/1",
"prefix": "kv/apisix",
"token": "root",
"uri": "127.0.0.1:8200"
}
]
}
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local values = secret.secrets()
ngx.say(#values)
}
}
--- request
GET /t
--- response_body
0
--- error_log
property "uri" validation failed: failed to match pattern "^[^\\/]+:\\/\\/([\\da-zA-Z.-]+|\\[[\\da-fA-F:]+\\])(:\\d+)?"
=== TEST 2: validate secrets: manager not exits
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"secrets": [
{
"id": "hhh/1",
"prefix": "kv/apisix",
"token": "root",
"uri": "127.0.0.1:8200"
}
]
}
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local values = secret.secrets()
ngx.say(#values)
}
}
--- request
GET /t
--- response_body
0
--- error_log
secret manager not exits
=== TEST 3: load config normal
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"secrets": [
{
"id": "vault/1",
"prefix": "kv/apisix",
"token": "root",
"uri": "http://127.0.0.1:8200"
}
]
}
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local values = secret.secrets()
ngx.say("len: ", #values)
ngx.say("id: ", values[1].value.id)
ngx.say("prefix: ", values[1].value.prefix)
ngx.say("token: ", values[1].value.token)
ngx.say("uri: ", values[1].value.uri)
}
}
--- request
GET /t
--- response_body
len: 1
id: vault/1
prefix: kv/apisix
token: root
uri: http://127.0.0.1:8200
=== TEST 4: store secret into vault
--- exec
VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/apisix-key key=value
--- response_body
Success! Data written to: kv/apisix/apisix-key
=== TEST 5: secret.fetch_by_uri: start with $secret://
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"secrets": [
{
"id": "vault/1",
"prefix": "kv/apisix",
"token": "root",
"uri": "http://127.0.0.1:8200"
}
]
}
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local value = secret.fetch_by_uri("$secret://vault/1/apisix-key/key")
ngx.say(value)
}
}
--- request
GET /t
--- response_body
value
=== TEST 6: secret.fetch_by_uri, wrong ref format: wrong type
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri(1)
ngx.say(err)
}
}
--- request
GET /t
--- response_body
error secret_uri type: number
=== TEST 7: secret.fetch_by_uri, wrong ref format: wrong prefix
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri("secret://")
ngx.say(err)
}
}
--- request
GET /t
--- response_body
error secret_uri prefix: secret://
=== TEST 8: secret.fetch_by_uri, error format: no secret manager
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri("$secret://")
ngx.say(err)
}
}
--- request
GET /t
--- response_body
error format: no secret manager
=== TEST 9: secret.fetch_by_uri, error format: no secret conf id
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri("$secret://vault/")
ngx.say(err)
}
}
--- request
GET /t
--- response_body
error format: no secret conf id
=== TEST 10: secret.fetch_by_uri, error format: no secret key id
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri("$secret://vault/2/")
ngx.say(err)
}
}
--- request
GET /t
--- response_body
error format: no secret key id
=== TEST 11: secret.fetch_by_uri, no config
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local _, err = secret.fetch_by_uri("$secret://vault/2/bar")
ngx.say(err)
}
}
--- request
GET /t
--- response_body
no secret conf, secret_uri: $secret://vault/2/bar
=== TEST 12: secret.fetch_by_uri, no sub key value
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"secrets": [
{
"id": "vault/1",
"prefix": "kv/apisix",
"token": "root",
"uri": "http://127.0.0.1:8200"
}
]
}
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local value = secret.fetch_by_uri("$secret://vault/1/apisix-key/bar")
ngx.say(value)
}
}
--- request
GET /t
--- response_body
nil
=== TEST 13: fetch_secrets env: no cache
--- main_config
env secret=apisix;
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local refs = {
key = "jack",
secret = "$env://secret"
}
local new_refs = secret.fetch_secrets(refs)
assert(new_refs ~= refs)
ngx.say(refs.secret)
ngx.say(new_refs.secret)
ngx.say(new_refs.key)
}
}
--- request
GET /t
--- response_body
$env://secret
apisix
jack
--- error_log_like
qr/retrieve secrets refs/
=== TEST 14: fetch_secrets env: cache
--- main_config
env secret=apisix;
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local refs = {
key = "jack",
secret = "$env://secret"
}
local refs_1 = secret.fetch_secrets(refs, true, "key", 1)
local refs_2 = secret.fetch_secrets(refs, true, "key", 1)
assert(refs_1 == refs_2)
ngx.say(refs_1.secret)
ngx.say(refs_2.secret)
}
}
--- request
GET /t
--- response_body
apisix
apisix
--- grep_error_log eval
qr/retrieve secrets refs/
--- grep_error_log_out
retrieve secrets refs
=== TEST 15: fetch_secrets env: table nesting
--- main_config
env secret=apisix;
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local refs = {
key = "jack",
user = {
username = "apisix",
passsword = "$env://secret"
}
}
local new_refs = secret.fetch_secrets(refs)
ngx.say(new_refs.user.passsword)
}
}
--- request
GET /t
--- response_body
apisix
=== TEST 16: fetch_secrets: wrong refs type
--- main_config
env secret=apisix;
--- config
location /t {
content_by_lua_block {
local secret = require("apisix.secret")
local refs = "wrong"
local new_refs = secret.fetch_secrets(refs)
ngx.say(new_refs)
}
}
--- request
GET /t
--- response_body
nil

View File

@@ -0,0 +1,191 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('debug');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
if (!$block->request) {
$block->set_value("request", "GET /t");
}
if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
if ($block->sslhandshake) {
my $sslhandshake = $block->sslhandshake;
$block->set_value("config", <<_EOC_)
listen unix:\$TEST_NGINX_HTML_DIR/nginx.sock ssl;
location /t {
content_by_lua_block {
-- sync
ngx.sleep(0.2)
do
local sock = ngx.socket.tcp()
sock:settimeout(2000)
local ok, err = sock:connect("unix:\$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end
$sslhandshake
local req = "GET /hello HTTP/1.0\\r\\nHost: test.com\\r\\nConnection: close\\r\\n\\r\\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send http request: ", err)
return
end
local line, err = sock:receive()
if not line then
ngx.say("failed to receive: ", err)
return
end
ngx.say("received: ", line)
local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end -- do
-- collectgarbage()
}
}
_EOC_
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"ssls": [
{
"cert": "-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIJAI3Meu/gJVTLMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDAeFw0yMDEwMjgwMzMzMDJaFw0yMTEwMjgwMzMzMDJaMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ/qwxCR7g5S\ns9+VleopkLi5pAszEkHYOBpwF/hDeRdxU0I0e1zZTdTlwwPy2vf8m3kwoq6fmNCt\ntdUUXh5Wvgi/2OA8HBBzaQFQL1Av9qWwyES5cx6p0ZBwIrcXQIsl1XfNSUpQNTSS\nD44TGduXUIdeshukPvMvLWLezynf2/WlgVh/haWtDG99r/Gj3uBdjl0m/xGvKvIv\nNFy6EdgG9fkwcIalutjrUnGl9moGjwKYu4eXW2Zt5el0d1AHXUsqK4voe0p+U2Nz\nquDmvxteXWdlsz8o5kQT6a4DUtWhpPIfNj9oZfPRs3LhBFQ74N70kVxMOCdec1lU\nbnFzLIMGlz0CAwEAAaNQME4wHQYDVR0OBBYEFFHeljijrr+SPxlH5fjHRPcC7bv2\nMB8GA1UdIwQYMBaAFFHeljijrr+SPxlH5fjHRPcC7bv2MAwGA1UdEwQFMAMBAf8w\nDQYJKoZIhvcNAQELBQADggEBAG6NNTK7sl9nJxeewVuogCdMtkcdnx9onGtCOeiQ\nqvh5Xwn9akZtoLMVEdceU0ihO4wILlcom3OqHs9WOd6VbgW5a19Thh2toxKidHz5\nrAaBMyZsQbFb6+vFshZwoCtOLZI/eIZfUUMFqMXlEPrKru1nSddNdai2+zi5rEnM\nHCot43+3XYuqkvWlOjoi9cP+C4epFYrxpykVbcrtbd7TK+wZNiK3xtDPnVzjdNWL\ngeAEl9xrrk0ss4nO/EreTQgS46gVU+tLC+b23m2dU7dcKZ7RDoiA9bdVc4a2IsaS\n2MvLL4NZ2nUh8hAEHiLtGMAV3C6xNbEyM07hEpDW6vk6tqk=\n-----END CERTIFICATE-----",
"key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCf6sMQke4OUrPf\nlZXqKZC4uaQLMxJB2DgacBf4Q3kXcVNCNHtc2U3U5cMD8tr3/Jt5MKKun5jQrbXV\nFF4eVr4Iv9jgPBwQc2kBUC9QL/alsMhEuXMeqdGQcCK3F0CLJdV3zUlKUDU0kg+O\nExnbl1CHXrIbpD7zLy1i3s8p39v1pYFYf4WlrQxvfa/xo97gXY5dJv8RryryLzRc\nuhHYBvX5MHCGpbrY61JxpfZqBo8CmLuHl1tmbeXpdHdQB11LKiuL6HtKflNjc6rg\n5r8bXl1nZbM/KOZEE+muA1LVoaTyHzY/aGXz0bNy4QRUO+De9JFcTDgnXnNZVG5x\ncyyDBpc9AgMBAAECggEAatcEtehZPJaCeClPPF/Cwbe9YoIfe4BCk186lHI3z7K1\n5nB7zt+bwVY0AUpagv3wvXoB5lrYVOsJpa9y5iAb3GqYMc/XDCKfD/KLea5hwfcn\nBctEn0LjsPVKLDrLs2t2gBDWG2EU+udunwQh7XTdp2Nb6V3FdOGbGAg2LgrSwP1g\n0r4z14F70oWGYyTQ5N8UGuyryVrzQH525OYl38Yt7R6zJ/44FVi/2TvdfHM5ss39\nSXWi00Q30fzaBEf4AdHVwVCRKctwSbrIOyM53kiScFDmBGRblCWOxXbiFV+d3bjX\ngf2zxs7QYZrFOzOO7kLtHGua4itEB02497v+1oKDwQKBgQDOBvCVGRe2WpItOLnj\nSF8iz7Sm+jJGQz0D9FhWyGPvrN7IXGrsXavA1kKRz22dsU8xdKk0yciOB13Wb5y6\nyLsr/fPBjAhPb4h543VHFjpAQcxpsH51DE0b2oYOWMmz+rXGB5Jy8EkP7Q4njIsc\n2wLod1dps8OT8zFx1jX3Us6iUQKBgQDGtKkfsvWi3HkwjFTR+/Y0oMz7bSruE5Z8\ng0VOHPkSr4XiYgLpQxjbNjq8fwsa/jTt1B57+By4xLpZYD0BTFuf5po+igSZhH8s\nQS5XnUnbM7d6Xr/da7ZkhSmUbEaMeHONSIVpYNgtRo4bB9Mh0l1HWdoevw/w5Ryt\nL/OQiPhfLQKBgQCh1iG1fPh7bbnVe/HI71iL58xoPbCwMLEFIjMiOFcINirqCG6V\nLR91Ytj34JCihl1G4/TmWnsH1hGIGDRtJLCiZeHL70u32kzCMkI1jOhFAWqoutMa\n7obDkmwraONIVW/kFp6bWtSJhhTQTD4adI9cPCKWDXdcCHSWj0Xk+U8HgQKBgBng\nt1HYhaLzIZlP/U/nh3XtJyTrX7bnuCZ5FhKJNWrYjxAfgY+NXHRYCKg5x2F5j70V\nbe7pLhxmCnrPTMKZhik56AaTBOxVVBaYWoewhUjV4GRAaK5Wc8d9jB+3RizPFwVk\nV3OU2DJ1SNZ+W2HBOsKrEfwFF/dgby6i2w6MuAP1AoGBAIxvxUygeT/6P0fHN22P\nzAHFI4v2925wYdb7H//D8DIADyBwv18N6YH8uH7L+USZN7e4p2k8MGGyvTXeC6aX\nIeVtU6fH57Ddn59VPbF20m8RCSkmBvSdcbyBmqlZSBE+fKwCliKl6u/GH0BNAWKz\nr8yiEiskqRmy7P7MY9hDmEbG\n-----END PRIVATE KEY-----",
"snis": [
"t.com",
"test.com"
]
}
]
}
--- sslhandshake
local sess, err = sock:sslhandshake(nil, "test.com", false)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end
--- response_body
received: HTTP/1.1 200 OK
close: 1 nil
--- error_log
server name: "test.com"
=== TEST 2: single sni
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}
],
"ssls": [
{
"cert": "-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIJAI3Meu/gJVTLMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDAeFw0yMDEwMjgwMzMzMDJaFw0yMTEwMjgwMzMzMDJaMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ/qwxCR7g5S\ns9+VleopkLi5pAszEkHYOBpwF/hDeRdxU0I0e1zZTdTlwwPy2vf8m3kwoq6fmNCt\ntdUUXh5Wvgi/2OA8HBBzaQFQL1Av9qWwyES5cx6p0ZBwIrcXQIsl1XfNSUpQNTSS\nD44TGduXUIdeshukPvMvLWLezynf2/WlgVh/haWtDG99r/Gj3uBdjl0m/xGvKvIv\nNFy6EdgG9fkwcIalutjrUnGl9moGjwKYu4eXW2Zt5el0d1AHXUsqK4voe0p+U2Nz\nquDmvxteXWdlsz8o5kQT6a4DUtWhpPIfNj9oZfPRs3LhBFQ74N70kVxMOCdec1lU\nbnFzLIMGlz0CAwEAAaNQME4wHQYDVR0OBBYEFFHeljijrr+SPxlH5fjHRPcC7bv2\nMB8GA1UdIwQYMBaAFFHeljijrr+SPxlH5fjHRPcC7bv2MAwGA1UdEwQFMAMBAf8w\nDQYJKoZIhvcNAQELBQADggEBAG6NNTK7sl9nJxeewVuogCdMtkcdnx9onGtCOeiQ\nqvh5Xwn9akZtoLMVEdceU0ihO4wILlcom3OqHs9WOd6VbgW5a19Thh2toxKidHz5\nrAaBMyZsQbFb6+vFshZwoCtOLZI/eIZfUUMFqMXlEPrKru1nSddNdai2+zi5rEnM\nHCot43+3XYuqkvWlOjoi9cP+C4epFYrxpykVbcrtbd7TK+wZNiK3xtDPnVzjdNWL\ngeAEl9xrrk0ss4nO/EreTQgS46gVU+tLC+b23m2dU7dcKZ7RDoiA9bdVc4a2IsaS\n2MvLL4NZ2nUh8hAEHiLtGMAV3C6xNbEyM07hEpDW6vk6tqk=\n-----END CERTIFICATE-----",
"key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCf6sMQke4OUrPf\nlZXqKZC4uaQLMxJB2DgacBf4Q3kXcVNCNHtc2U3U5cMD8tr3/Jt5MKKun5jQrbXV\nFF4eVr4Iv9jgPBwQc2kBUC9QL/alsMhEuXMeqdGQcCK3F0CLJdV3zUlKUDU0kg+O\nExnbl1CHXrIbpD7zLy1i3s8p39v1pYFYf4WlrQxvfa/xo97gXY5dJv8RryryLzRc\nuhHYBvX5MHCGpbrY61JxpfZqBo8CmLuHl1tmbeXpdHdQB11LKiuL6HtKflNjc6rg\n5r8bXl1nZbM/KOZEE+muA1LVoaTyHzY/aGXz0bNy4QRUO+De9JFcTDgnXnNZVG5x\ncyyDBpc9AgMBAAECggEAatcEtehZPJaCeClPPF/Cwbe9YoIfe4BCk186lHI3z7K1\n5nB7zt+bwVY0AUpagv3wvXoB5lrYVOsJpa9y5iAb3GqYMc/XDCKfD/KLea5hwfcn\nBctEn0LjsPVKLDrLs2t2gBDWG2EU+udunwQh7XTdp2Nb6V3FdOGbGAg2LgrSwP1g\n0r4z14F70oWGYyTQ5N8UGuyryVrzQH525OYl38Yt7R6zJ/44FVi/2TvdfHM5ss39\nSXWi00Q30fzaBEf4AdHVwVCRKctwSbrIOyM53kiScFDmBGRblCWOxXbiFV+d3bjX\ngf2zxs7QYZrFOzOO7kLtHGua4itEB02497v+1oKDwQKBgQDOBvCVGRe2WpItOLnj\nSF8iz7Sm+jJGQz0D9FhWyGPvrN7IXGrsXavA1kKRz22dsU8xdKk0yciOB13Wb5y6\nyLsr/fPBjAhPb4h543VHFjpAQcxpsH51DE0b2oYOWMmz+rXGB5Jy8EkP7Q4njIsc\n2wLod1dps8OT8zFx1jX3Us6iUQKBgQDGtKkfsvWi3HkwjFTR+/Y0oMz7bSruE5Z8\ng0VOHPkSr4XiYgLpQxjbNjq8fwsa/jTt1B57+By4xLpZYD0BTFuf5po+igSZhH8s\nQS5XnUnbM7d6Xr/da7ZkhSmUbEaMeHONSIVpYNgtRo4bB9Mh0l1HWdoevw/w5Ryt\nL/OQiPhfLQKBgQCh1iG1fPh7bbnVe/HI71iL58xoPbCwMLEFIjMiOFcINirqCG6V\nLR91Ytj34JCihl1G4/TmWnsH1hGIGDRtJLCiZeHL70u32kzCMkI1jOhFAWqoutMa\n7obDkmwraONIVW/kFp6bWtSJhhTQTD4adI9cPCKWDXdcCHSWj0Xk+U8HgQKBgBng\nt1HYhaLzIZlP/U/nh3XtJyTrX7bnuCZ5FhKJNWrYjxAfgY+NXHRYCKg5x2F5j70V\nbe7pLhxmCnrPTMKZhik56AaTBOxVVBaYWoewhUjV4GRAaK5Wc8d9jB+3RizPFwVk\nV3OU2DJ1SNZ+W2HBOsKrEfwFF/dgby6i2w6MuAP1AoGBAIxvxUygeT/6P0fHN22P\nzAHFI4v2925wYdb7H//D8DIADyBwv18N6YH8uH7L+USZN7e4p2k8MGGyvTXeC6aX\nIeVtU6fH57Ddn59VPbF20m8RCSkmBvSdcbyBmqlZSBE+fKwCliKl6u/GH0BNAWKz\nr8yiEiskqRmy7P7MY9hDmEbG\n-----END PRIVATE KEY-----",
"sni": "test.com"
}
]
}
--- sslhandshake
local sess, err = sock:sslhandshake(nil, "test.com", false)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end
--- response_body
received: HTTP/1.1 200 OK
close: 1 nil
--- error_log
server name: "test.com"
=== TEST 3: bad cert
--- apisix_json
{
"routes": [
{
"uri": "/hello",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
},
"ssl_enable": true
}
],
"ssls": [
{
"cert": "-----BEGIN CERTIFICATE-----\nMIIDrzCCApegAwIBAgIJAI3Meu/gJVTLMA0GCSqGSIb3DQEBCwUAMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDAeFw0yMDEwMjgwMzMzMDJaFw0yMTEwMjgwMzMzMDJaMG4xCzAJBgNV\nBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ3pob3UxDTAL\nBgNVBAoMBHRlc3QxDTALBgNVBAsMBHRlc3QxGzAZBgNVBAMMEmV0Y2QuY2x1c3Rl\nci5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ/qwxCR7g5S\ns9+VleopkLi5pAszEkHYOBpwF/hDeRdxU0I0e1zZTdTlwwPy2vf8m3kwoq6fmNCt\ntdUUXh5Wvgi/2OA8HBBzaQFQL1Av9qWwyES5cx6p0ZBwIrcXQIsl1XfNSUpQNTSS\nD44TGduXUIdeshukPvMvLWLezynf2/WlgVh/haWtDG99r/Gj3uBdjl0m/xGvKvIv\nquDmvxteXWdlsz8o5kQT6a4DUtWhpPIfNj9oZfPRs3LhBFQ74N70kVxMOCdec1lU\nbnFzLIMGlz0CAwEAAaNQME4wHQYDVR0OBBYEFFHeljijrr+SPxlH5fjHRPcC7bv2\nMB8GA1UdIwQYMBaAFFHeljijrr+SPxlH5fjHRPcC7bv2MAwGA1UdEwQFMAMBAf8w\nDQYJKoZIhvcNAQELBQADggEBAG6NNTK7sl9nJxeewVuogCdMtkcdnx9onGtCOeiQ\nqvh5Xwn9akZtoLMVEdceU0ihO4wILlcom3OqHs9WOd6VbgW5a19Thh2toxKidHz5\nrAaBMyZsQbFb6+vFshZwoCtOLZI/eIZfUUMFqMXlEPrKru1nSddNdai2+zi5rEnM\nHCot43+3XYuqkvWlOjoi9cP+C4epFYrxpykVbcrtbd7TK+wZNiK3xtDPnVzjdNWL\ngeAEl9xrrk0ss4nO/EreTQgS46gVU+tLC+b23m2dU7dcKZ7RDoiA9bdVc4a2IsaS\n2MvLL4NZ2nUh8hAEHiLtGMAV3C6xNbEyM07hEpDW6vk6tqk=\n-----END CERTIFICATE-----",
"key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCf6sMQke4OUrPf\nlZXqKZC4uaQLMxJB2DgacBf4Q3kXcVNCNHtc2U3U5cMD8tr3/Jt5MKKun5jQrbXV\nFF4eVr4Iv9jgPBwQc2kBUC9QL/alsMhEuXMeqdGQcCK3F0CLJdV3zUlKUDU0kg+O\nExnbl1CHXrIbpD7zLy1i3s8p39v1pYFYf4WlrQxvfa/xo97gXY5dJv8RryryLzRc\nuhHYBvX5MHCGpbrY61JxpfZqBo8CmLuHl1tmbeXpdHdQB11LKiuL6HtKflNjc6rg\n5r8bXl1nZbM/KOZEE+muA1LVoaTyHzY/aGXz0bNy4QRUO+De9JFcTDgnXnNZVG5x\ncyyDBpc9AgMBAAECggEAatcEtehZPJaCeClPPF/Cwbe9YoIfe4BCk186lHI3z7K1\n5nB7zt+bwVY0AUpagv3wvXoB5lrYVOsJpa9y5iAb3GqYMc/XDCKfD/KLea5hwfcn\nBctEn0LjsPVKLDrLs2t2gBDWG2EU+udunwQh7XTdp2Nb6V3FdOGbGAg2LgrSwP1g\n0r4z14F70oWGYyTQ5N8UGuyryVrzQH525OYl38Yt7R6zJ/44FVi/2TvdfHM5ss39\nSXWi00Q30fzaBEf4AdHVwVCRKctwSbrIOyM53kiScFDmBGRblCWOxXbiFV+d3bjX\ngf2zxs7QYZrFOzOO7kLtHGua4itEB02497v+1oKDwQKBgQDOBvCVGRe2WpItOLnj\nSF8iz7Sm+jJGQz0D9FhWyGPvrN7IXGrsXavA1kKRz22dsU8xdKk0yciOB13Wb5y6\nyLsr/fPBjAhPb4h543VHFjpAQcxpsH51DE0b2oYOWMmz+rXGB5Jy8EkP7Q4njIsc\n2wLod1dps8OT8zFx1jX3Us6iUQKBgQDGtKkfsvWi3HkwjFTR+/Y0oMz7bSruE5Z8\ng0VOHPkSr4XiYgLpQxjbNjq8fwsa/jTt1B57+By4xLpZYD0BTFuf5po+igSZhH8s\nQS5XnUnbM7d6Xr/da7ZkhSmUbEaMeHONSIVpYNgtRo4bB9Mh0l1HWdoevw/w5Ryt\nL/OQiPhfLQKBgQCh1iG1fPh7bbnVe/HI71iL58xoPbCwMLEFIjMiOFcINirqCG6V\nLR91Ytj34JCihl1G4/TmWnsH1hGIGDRtJLCiZeHL70u32kzCMkI1jOhFAWqoutMa\n7obDkmwraONIVW/kFp6bWtSJhhTQTD4adI9cPCKWDXdcCHSWj0Xk+U8HgQKBgBng\nt1HYhaLzIZlP/U/nh3XtJyTrX7bnuCZ5FhKJNWrYjxAfgY+NXHRYCKg5x2F5j70V\nbe7pLhxmCnrPTMKZhik56AaTBOxVVBaYWoewhUjV4GRAaK5Wc8d9jB+3RizPFwVk\nV3OU2DJ1SNZ+W2HBOsKrEfwFF/dgby6i2w6MuAP1AoGBAIxvxUygeT/6P0fHN22P\nzAHFI4v2925wYdb7H//D8DIADyBwv18N6YH8uH7L+USZN7e4p2k8MGGyvTXeC6aX\nIeVtU6fH57Ddn59VPbF20m8RCSkmBvSdcbyBmqlZSBE+fKwCliKl6u/GH0BNAWKz\nr8yiEiskqRmy7P7MY9hDmEbG\n-----END PRIVATE KEY-----",
"snis": [
"t.com",
"test.com"
]
}
]
}
--- error_log
failed to parse cert
--- error_code: 404

View File

@@ -0,0 +1,148 @@
#
# 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.
#
use t::APISIX 'no_plan';
repeat_each(1);
log_level('info');
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
$block->set_value("stream_enable", 1);
if (!$block->stream_request) {
$block->set_value("stream_request", "mmm");
}
if (!$block->error_log && !$block->no_error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});
run_tests();
__DATA__
=== TEST 1: sanity
--- apisix_json
{
"stream_routes": [
{
"server_addr": "127.0.0.1",
"server_port": 1985,
"id": 1,
"upstream": {
"nodes": {
"127.0.0.1:1995": 1
},
"type": "roundrobin"
}
}
]
}
--- stream_response
hello world
=== TEST 2: rule with bad plugin
--- apisix_json
{
"stream_routes": [
{
"server_addr": "127.0.0.1",
"server_port": 1985,
"id": 1,
"plugins": {
"mqtt-proxy": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1995": 1
},
"type": "roundrobin"
}
}
]
}
--- error_log eval
qr/property "\w+" is required/
=== TEST 3: ignore unknown plugin
--- apisix_json
{
"stream_routes": [
{
"server_addr": "127.0.0.1",
"server_port": 1985,
"id": 1,
"plugins": {
"x-rewrite": {
"uri": 1
}
},
"upstream": {
"nodes": {
"127.0.0.1:1995": 1
},
"type": "roundrobin"
}
}
]
}
--- stream_response
hello world
=== TEST 4: sanity with plugin
--- apisix_json
{
"stream_routes": [
{
"server_addr": "127.0.0.1",
"server_port": 1985,
"id": 1,
"upstream_id": 1,
"plugins": {
"mqtt-proxy": {
"protocol_name": "MQTT",
"protocol_level": 4
}
}
}
],
"upstreams": [
{
"nodes": {
"127.0.0.1:1995": 1
},
"type": "roundrobin",
"id": 1
}
]
}
--- stream_request eval
"\x10\x0f\x00\x04\x4d\x51\x54\x54\x04\x02\x00\x3c\x00\x03\x66\x6f\x6f"
--- stream_response
hello world