Skip to content

Commit

Permalink
fix: ensure the plugin is always reloaded
Browse files Browse the repository at this point in the history
Only trigger a reset from admin when the etcd's data is different
from the one of admin. So there is no need to add check in node side.

Fix #4314

Signed-off-by: spacewander <spacewanderlzx@gmail.com>
  • Loading branch information
spacewander committed May 27, 2021
1 parent 709561a commit 6ff2e43
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 40 deletions.
27 changes: 27 additions & 0 deletions apisix/admin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,32 @@ local function post_reload_plugins()
end


local function plugins_eq(old, new)
local old_set = {}
for _, p in ipairs(old) do
old_set[p.name] = p
end

local new_set = {}
for _, p in ipairs(new) do
new_set[p.name] = p
end

return core.table.set_eq(old_set, new_set)
end


local function sync_local_conf_to_etcd()
core.log.warn("sync local conf to etcd")

-- we can assume each admin has same configuration so there is no need
-- for transaction
local res, err = core.etcd.get("/plugins")
if not res then
core.log.error("failed to get current plugins: ", err)
return
end

local local_conf = core.config.local_conf()

local plugins = {}
Expand All @@ -305,6 +328,10 @@ local function sync_local_conf_to_etcd()
})
end

if plugins_eq(res, plugins) then
core.log.info("plugins not changed, don't need to reset")
end

-- need to store all plugins name into one key so that it can be updated atomically
local res, err = core.etcd.set("/plugins", plugins)
if not res then
Expand Down
31 changes: 0 additions & 31 deletions apisix/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,6 @@ local function load_plugin(name, plugins_list, is_stream_plugin)
end


local function plugins_eq(old, new)
local eq = core.table.set_eq(old, new)
if not eq then
core.log.info("plugin list changed")
return false
end

for name, plugin in pairs(old) do
eq = core.table.deep_eq(plugin.attr, plugin_attr(name))
if not eq then
core.log.info("plugin_attr of ", name, " changed")
return false
end
end

return true
end


local function load(plugin_names)
local processed = {}
for _, name in ipairs(plugin_names) do
Expand All @@ -164,12 +145,6 @@ local function load(plugin_names)
end
end

-- the same configure may be synchronized more than one
if plugins_eq(local_plugins_hash, processed) then
core.log.info("plugins not changed")
return true
end

core.log.warn("new plugins: ", core.json.delay_encode(processed))

for name in pairs(local_plugins_hash) do
Expand Down Expand Up @@ -212,12 +187,6 @@ local function load_stream(plugin_names)
end
end

-- the same configure may be synchronized more than one
if plugins_eq(stream_local_plugins_hash, processed) then
core.log.info("plugins not changed")
return true
end

core.log.warn("new plugins: ", core.json.delay_encode(processed))

for name in pairs(stream_local_plugins_hash) do
Expand Down
98 changes: 89 additions & 9 deletions t/admin/plugins-reload.t
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ __DATA__
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
-- now the plugin will be loaded twice,
-- one during startup and the other one by reload
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
Expand All @@ -55,14 +57,10 @@ GET /t
--- response_body
done
--- error_log
load plugin times: 1
load plugin times: 1
load plugin times: 2
load plugin times: 2
start to hot reload plugins
start to hot reload plugins
load(): plugins not changed
load_stream(): plugins not changed
load(): plugins not changed
load_stream(): plugins not changed
Expand Down Expand Up @@ -180,6 +178,7 @@ plugin_attr:
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
ngx.say(org_body)
ngx.sleep(0.1)
}
}
--- request
Expand All @@ -196,9 +195,9 @@ example-plugin get plugin attr val: 0
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
--- error_log
plugin_attr of example-plugin changed
plugins not changed
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
example-plugin get plugin attr val: 1
Expand Down Expand Up @@ -301,3 +300,84 @@ done
qr/Instance report fails/
--- grep_error_log_out
Instance report fails
=== TEST 6: check disabling plugin via etcd
--- 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": {
"echo": {
"body":"hello upstream\n"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 7: hit
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
--- request
GET /hello
--- response_body
hello upstream
=== TEST 8: hit after disabling echo
--- yaml_config
apisix:
node_listen: 1984
enable_admin: false
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
assert(etcd.set("/plugins", {{name = "jwt-auth"}}))
ngx.sleep(0.2)
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)
if not res then
ngx.say(err)
return
end
ngx.print(res.body)
}
}
--- request
GET /t
--- response_body
hello world

0 comments on commit 6ff2e43

Please sign in to comment.