You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by mo...@apache.org on 2023/04/06 03:35:47 UTC
[apisix] branch master updated: fix: check upstream reference in traffic-split plugin when delete upstream (#9044)
This is an automated email from the ASF dual-hosted git repository.
monkeydluffy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new dff1c7671 fix: check upstream reference in traffic-split plugin when delete upstream (#9044)
dff1c7671 is described below
commit dff1c767134920cb3c54c918d6166ab6813af00d
Author: Tristan <ji...@foxmail.com>
AuthorDate: Thu Apr 6 11:35:38 2023 +0800
fix: check upstream reference in traffic-split plugin when delete upstream (#9044)
---
apisix/admin/upstreams.lua | 105 ++++++++--
apisix/consumer_group.lua | 8 +
apisix/plugin_config.lua | 8 +
t/admin/upstream5.t | 486 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 589 insertions(+), 18 deletions(-)
diff --git a/apisix/admin/upstreams.lua b/apisix/admin/upstreams.lua
index a85d24d8d..687e09cd4 100644
--- a/apisix/admin/upstreams.lua
+++ b/apisix/admin/upstreams.lua
@@ -15,13 +15,17 @@
-- limitations under the License.
--
local core = require("apisix.core")
+local config_util = require("apisix.core.config_util")
+local router = require("apisix.router")
local get_routes = require("apisix.router").http_routes
local get_services = require("apisix.http.service").services
+local get_plugin_configs = require("apisix.plugin_config").plugin_configs
+local get_consumers = require("apisix.consumer").consumers
+local get_consumer_groups = require("apisix.consumer_group").consumer_groups
local apisix_upstream = require("apisix.upstream")
local resource = require("apisix.admin.resource")
local tostring = tostring
local ipairs = ipairs
-local type = type
local function check_conf(id, conf, need_id)
@@ -34,31 +38,96 @@ local function check_conf(id, conf, need_id)
end
-local function delete_checker(id)
- local routes, routes_ver = get_routes()
- if routes_ver and routes then
- for _, route in ipairs(routes) do
- if type(route) == "table" and route.value
- and route.value.upstream_id
- and tostring(route.value.upstream_id) == id then
- return 400, {error_msg = "can not delete this upstream,"
- .. " route [" .. route.value.id
+local function up_id_in_plugins(plugins, up_id)
+ if plugins and plugins["traffic-split"]
+ and plugins["traffic-split"].rules then
+
+ for _, rule in ipairs(plugins["traffic-split"].rules) do
+ local plugin_upstreams = rule.weighted_upstreams
+ for _, plugin_upstream in ipairs(plugin_upstreams) do
+ if plugin_upstream.upstream_id
+ and tostring(plugin_upstream.upstream_id) == up_id then
+ return true
+ end
+ end
+ end
+
+ return false
+ end
+end
+
+
+local function check_resources_reference(resources, up_id,
+ only_check_plugin, resources_name)
+ if resources then
+ for _, resource in config_util.iterate_values(resources) do
+ if resource and resource.value then
+ if up_id_in_plugins(resource.value.plugins, up_id) then
+ return {error_msg = "can not delete this upstream,"
+ .. " plugin in "
+ .. resources_name .. " ["
+ .. resource.value.id
+ .. "] is still using it now"}
+ end
+
+ if not only_check_plugin and resource.value.upstream_id
+ and tostring(resource.value.upstream_id) == up_id then
+ return {error_msg = "can not delete this upstream, "
+ .. resources_name .. " [" .. resource.value.id
.. "] is still using it now"}
+ end
end
end
end
+end
+
+
+local function delete_checker(id)
+ local routes = get_routes()
+ local err_msg = check_resources_reference(routes, id, false, "route")
+ if err_msg then
+ return 400, err_msg
+ end
local services, services_ver = get_services()
core.log.info("services: ", core.json.delay_encode(services, true))
core.log.info("services_ver: ", services_ver)
- if services_ver and services then
- for _, service in ipairs(services) do
- if type(service) == "table" and service.value
- and service.value.upstream_id
- and tostring(service.value.upstream_id) == id then
- return 400, {error_msg = "can not delete this upstream,"
- .. " service [" .. service.value.id
- .. "] is still using it now"}
+ local err_msg = check_resources_reference(services, id, false, "service")
+ if err_msg then
+ return 400, err_msg
+ end
+
+ local plugin_configs = get_plugin_configs()
+ local err_msg = check_resources_reference(plugin_configs, id, true, "plugin_config")
+ if err_msg then
+ return 400, err_msg
+ end
+
+ local consumers = get_consumers()
+ local err_msg = check_resources_reference(consumers, id, true, "consumer")
+ if err_msg then
+ return 400, err_msg
+ end
+
+ local consumer_groups = get_consumer_groups()
+ local err_msg = check_resources_reference(consumer_groups, id, true, "consumer_group")
+ if err_msg then
+ return 400, err_msg
+ end
+
+ -- TODO: Refactor router.global_rules and then refactor the following code
+ local global_rules = router.global_rules
+ if global_rules and global_rules.values
+ and #global_rules.values > 0 then
+
+ for _, global_rule in config_util.iterate_values(global_rules.values) do
+ if global_rule and global_rule.value
+ and global_rule.value.plugins
+ and up_id_in_plugins(global_rule.value.plugins, id) then
+ return 400, {error_msg = "can not delete this upstream,"
+ .. " plugin in global_rule ["
+ .. global_rule.value.id
+ .. "] is still using it now"}
end
end
end
diff --git a/apisix/consumer_group.lua b/apisix/consumer_group.lua
index 8c17bdd71..3be59ec92 100644
--- a/apisix/consumer_group.lua
+++ b/apisix/consumer_group.lua
@@ -39,6 +39,14 @@ function _M.init_worker()
end
+function _M.consumer_groups()
+ if not consumer_groups then
+ return nil, nil
+ end
+ return consumer_groups.values, consumer_groups.conf_version
+end
+
+
function _M.get(id)
return consumer_groups:get(id)
end
diff --git a/apisix/plugin_config.lua b/apisix/plugin_config.lua
index cc5a6ff38..828ebf1e2 100644
--- a/apisix/plugin_config.lua
+++ b/apisix/plugin_config.lua
@@ -40,6 +40,14 @@ function _M.init_worker()
end
+function _M.plugin_configs()
+ if not plugin_configs then
+ return nil, nil
+ end
+ return plugin_configs.values, plugin_configs.conf_version
+end
+
+
function _M.get(id)
return plugin_configs:get(id)
end
diff --git a/t/admin/upstream5.t b/t/admin/upstream5.t
index 9fd59bfe7..f589a415d 100644
--- a/t/admin/upstream5.t
+++ b/t/admin/upstream5.t
@@ -111,3 +111,489 @@ passed
}
--- response_body
passed
+
+
+
+=== TEST 4: prepare upstream
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_PUT, [[{
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 5: prepare route
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/routes/1", ngx.HTTP_PUT, [[{
+ "plugins": {
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/hello"
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 6: delete upstream when plugin in route still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in route [1] is still using it now"}
+
+
+
+=== TEST 7: delete route
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/routes/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 8: prepare service
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/services/1", ngx.HTTP_PUT, [[{
+ "plugins": {
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 9: delete upstream when plugin in service still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in service [1] is still using it now"}
+
+
+
+=== TEST 10: delete service
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/services/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 11: prepare global_rule
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+
+ local code, body = t("/apisix/admin/global_rules/1", ngx.HTTP_PUT, [[{
+ "plugins": {
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 12: delete upstream when plugin in global_rule still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in global_rule [1] is still using it now"}
+
+
+
+=== TEST 13: delete global_rule
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/global_rules/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 14: prepare plugin_config
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+
+ local code, body = t("/apisix/admin/plugin_configs/1", ngx.HTTP_PUT, [[{
+ "plugins": {
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 15: delete upstream when plugin in plugin_config still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in plugin_config [1] is still using it now"}
+
+
+
+=== TEST 16: delete plugin_config
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/plugin_configs/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 17: prepare consumer
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+
+ local code, body = t("/apisix/admin/consumers", ngx.HTTP_PUT, [[{
+ "username": "test",
+ "plugins": {
+ "key-auth": {
+ "key": "auth-one"
+ },
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 18: delete upstream when plugin in consumer still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in consumer [test] is still using it now"}
+
+
+
+=== TEST 19: delete consumer
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/consumers/test", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 20: prepare consumer_group
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+
+ local code, body = t("/apisix/admin/consumer_groups/1", ngx.HTTP_PUT, [[{
+ "plugins": {
+ "key-auth": {
+ "key": "auth-one"
+ },
+ "traffic-split": {
+ "rules": [
+ {
+ "weighted_upstreams": [
+ {
+ "upstream_id": 1,
+ "weight": 1
+ },
+ {
+ "weight": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }]])
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 21: delete upstream when plugin in consumer_group still refer it
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"can not delete this upstream, plugin in consumer_group [1] is still using it now"}
+
+
+
+=== TEST 22: delete consumer_group
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/consumer_groups/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 23: delete upstream
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t("/apisix/admin/upstreams/1", ngx.HTTP_DELETE)
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed