This is an automated email from the ASF dual-hosted git repository.
shreemaan-abhishek 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 a508d83de4 fix(plugin): align unavailable plugin handling (#13928)
a508d83de4 is described below
commit a508d83de4a6aed4ab31dce728f9d3578d80f58c
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Fri Sep 11 18:36:45 2026 +0800
fix(plugin): align unavailable plugin handling (#13928)
---
apisix/core/config_etcd.lua | 2 +-
apisix/plugin.lua | 15 +++-
t/core/plugin-checker.t | 181 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 194 insertions(+), 4 deletions(-)
diff --git a/apisix/core/config_etcd.lua b/apisix/core/config_etcd.lua
index c6b4697c8b..7f41dd7a0a 100644
--- a/apisix/core/config_etcd.lua
+++ b/apisix/core/config_etcd.lua
@@ -563,7 +563,7 @@ local function load_full_data(self, dir_res, headers,
prev_values, prev_values_h
end
if data_valid and self.checker then
- data_valid, err = self.checker(item.value)
+ data_valid, err = self.checker(item.value, item.key)
if not data_valid then
log.error("failed to check item data of [", self.key,
"] err:", err, " ,val: ",
json.delay_encode(item.value))
diff --git a/apisix/plugin.lua b/apisix/plugin.lua
index 5a7a405a09..632e25c74c 100644
--- a/apisix/plugin.lua
+++ b/apisix/plugin.lua
@@ -162,6 +162,13 @@ local function check_disable(plugin_conf)
return plugin_conf._meta.disable
end
+
+
+local function warn_unavailable_plugin(name, plugin_conf)
+ if check_disable(plugin_conf) ~= true then
+ core.log.warn("plugin [", name, "] is not enabled and will be skipped")
+ end
+end
-- exposed for callers that must not act on a plugin config which never runs,
-- such as the control API reporting the health checkers a plugin owns
_M.check_disable = check_disable
@@ -1016,8 +1023,7 @@ local function check_single_plugin_schema(name,
plugin_conf, schema_type, skip_d
end
if skip_disabled_plugin then
- core.log.warn("skipping check schema for disabled or unknown
plugin [",
- name, "]. Enable the plugin or modify
configuration")
+ warn_unavailable_plugin(name, plugin_conf)
return true
else
return false, "unknown plugin [" .. name .. "]"
@@ -1271,6 +1277,7 @@ local function stream_check_schema(plugins_conf,
schema_type, skip_disabled_plug
local plugin_obj = stream_local_plugins_hash[name]
if not plugin_obj then
if skip_disabled_plugin then
+ warn_unavailable_plugin(name, plugin_conf)
goto CONTINUE
else
return false, "unknown plugin [" .. name .. "]"
@@ -1318,7 +1325,9 @@ end
function _M.stream_plugin_checker(item, in_cp)
if item.plugins then
- local skip_disabled_plugins = not in_cp
+ -- config_etcd passes the key as the second checker argument, so only
+ -- an explicit boolean marks validation on the control plane.
+ local skip_disabled_plugins = in_cp ~= true
if core.config.type == "yaml" or core.config.type == "json" then
skip_disabled_plugins = false
end
diff --git a/t/core/plugin-checker.t b/t/core/plugin-checker.t
new file mode 100644
index 0000000000..8e44ce5c85
--- /dev/null
+++ b/t/core/plugin-checker.t
@@ -0,0 +1,181 @@
+#
+# 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';
+
+no_root_location();
+no_long_string();
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: control-plane stream validation rejects an unavailable plugin
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").stream_plugin_checker
+ local ok, err = checker({plugins = {missing = {}}}, true)
+ ngx.say(ok or false, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+false: unknown plugin [missing]
+
+
+
+=== TEST 2: an etcd key identifies tolerant data-plane stream validation
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").stream_plugin_checker
+ local ok, err = checker({plugins = {missing = {}}},
+ "/apisix/stream_routes/1")
+ ngx.say(ok, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+true: nil
+--- error_log
+plugin [missing] is not enabled and will be skipped
+
+
+
+=== TEST 3: an explicitly disabled unavailable stream plugin is silent
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").stream_plugin_checker
+ local ok, err = checker({
+ plugins = {missing = {_meta = {disable = true}}}
+ }, "/apisix/stream_routes/1")
+ ngx.say(ok, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+true: nil
+--- no_error_log
+plugin [missing] is not enabled and will be skipped
+
+
+
+=== TEST 4: tolerant HTTP validation warns about an unavailable plugin
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").check_schema
+ local ok, err = checker({missing = {}}, nil, true)
+ ngx.say(ok, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+true: nil
+--- error_log
+plugin [missing] is not enabled and will be skipped
+
+
+
+=== TEST 5: an explicitly disabled unavailable HTTP plugin is silent
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").check_schema
+ local ok, err = checker({
+ missing = {_meta = {disable = true}}
+ }, nil, true)
+ ngx.say(ok, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+true: nil
+--- no_error_log
+plugin [missing] is not enabled and will be skipped
+
+
+
+=== TEST 6: single-item full loading passes the etcd key to its checker
+--- config
+ location /t {
+ content_by_lua_block {
+ local config_etcd = require("apisix.core.config_etcd")
+ local etcd = require("apisix.core.etcd")
+ local original_get_format = etcd.get_format
+ local etcd_cli = {}
+
+ function etcd_cli.readdir()
+ return {
+ status = 200,
+ headers = {},
+ body = {header = {revision = 1}, kvs = {}},
+ }
+ end
+
+ etcd.get_format = function(res)
+ res.body = {
+ node = {
+ key = "/apisix/plugins",
+ value = {{name = "jwt-auth"}},
+ modifiedIndex = 1,
+ },
+ }
+ return res
+ end
+
+ config_etcd.test_sync_data({
+ etcd_cli = etcd_cli,
+ key = "/apisix/plugins",
+ single_item = true,
+ need_reload = true,
+ checker = function(_, key)
+ ngx.say(key)
+ return true
+ end,
+ upgrade_version = function() end,
+ conf_version = 1,
+ })
+ etcd.get_format = original_get_format
+ }
+ }
+--- request
+GET /t
+--- response_body
+/apisix/plugins
+
+
+
+=== TEST 7: strict HTTP validation rejects an unavailable plugin
+--- config
+ location /t {
+ content_by_lua_block {
+ local checker = require("apisix.plugin").check_schema
+ local ok, err = checker({missing = {}}, nil, false)
+ ngx.say(ok or false, ": ", err)
+ }
+ }
+--- request
+GET /t
+--- response_body
+false: unknown plugin [missing]