From eceba6fe184594fb5e837d1497f6046d6ab8759b Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Fri, 2 Feb 2024 20:05:30 +0530 Subject: [PATCH 1/9] feat(control): add plugins_reload to control api Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/control/v1.lua | 13 +++++++++ docs/en/latest/control-api.md | 6 ++++ t/control/plugins-reload.t | 52 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 t/control/plugins-reload.t diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index 6838ee4cbe64..52fb6bd2fe5c 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -400,6 +400,13 @@ function _M.dump_plugin_metadata() return 200, metadata.value end +function _M.plugins_reload() + core.log.info("start to hot reload plugins") + plugin.load() + + return 200, "done" +end + return { -- /v1/schema @@ -474,5 +481,11 @@ return { uris = {"/plugin_metadata/*"}, handler = _M.dump_plugin_metadata, }, + -- /v1/plugins_reload + { + methods = {"POST"}, + uris = {"/plugins_reload"}, + handler = _M.plugins_reload, + }, get_health_checkers = _get_health_checkers, } diff --git a/docs/en/latest/control-api.md b/docs/en/latest/control-api.md index e21ca86d502d..c6b23ffbc67f 100644 --- a/docs/en/latest/control-api.md +++ b/docs/en/latest/control-api.md @@ -475,3 +475,9 @@ Dumps the metadata with the specified `plugin_name`: "id": "file-logger" } ``` + +### POST /v1/plugins_reload + +Introduced in [v3.9.0](https://github.com/apache/apisix/releases/tag/3.9.0) + +Triggers a hot reload of the plugins. diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t new file mode 100644 index 000000000000..45523e9ca849 --- /dev/null +++ b/t/control/plugins-reload.t @@ -0,0 +1,52 @@ +# +# 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); +no_long_string(); +no_root_location(); +no_shuffle(); +log_level("info"); + +our $yaml_config = <<_EOC_; +apisix: + enable_control: true + node_listen: 1984 +_EOC_ + +run_tests(); + +__DATA__ + +=== TEST 1: test plugins-reload +--- yaml_config eval: $::yaml_config +--- config + location /t { + content_by_lua_block { + local json = require("toolkit.json") + local t = require("lib.test_admin") + + local code, body, res = t.test('/v1/plugins_reload', + ngx.HTTP_POST) + ngx.say(res) + } + } +--- request +GET /t +--- error_code: 200 +--- response_body +done From 510bbfe3675c736b37772ce25a6ed2c9aa4ef72d Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Mon, 5 Feb 2024 22:29:28 +0530 Subject: [PATCH 2/9] fix: send reload event to workers Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/control/router.lua | 14 +++++++++++++- apisix/control/v1.lua | 15 +++++++++------ apisix/init.lua | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/apisix/control/router.lua b/apisix/control/router.lua index 851dbc872f3b..58418e4daa92 100644 --- a/apisix/control/router.lua +++ b/apisix/control/router.lua @@ -27,7 +27,7 @@ local pairs = pairs local type = type local ngx = ngx local get_method = ngx.req.get_method - +local events = require("apisix.events") local _M = {} @@ -198,5 +198,17 @@ end end -- do +local function reload_plugins() + core.log.info("start to hot reload plugins") + plugin_mod.load() + + return 200, "done" +end + + +function _M.init_worker() + -- register reload plugin handler + events:register(reload_plugins, builtin_v1_routes.RELOAD_EVENT, "PUT") +end return _M diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index 52fb6bd2fe5c..feccfed27514 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -26,10 +26,12 @@ local ipairs = ipairs local pcall = pcall local str_format = string.format local ngx_var = ngx.var +local events = require("apisix.events") local _M = {} +_M.RELOAD_EVENT = "plugin-reload" function _M.schema() local http_plugins, stream_plugins = plugin.get_all({ @@ -400,14 +402,15 @@ function _M.dump_plugin_metadata() return 200, metadata.value end -function _M.plugins_reload() - core.log.info("start to hot reload plugins") - plugin.load() +function _M.post_reload_plugins() + local success, err = events:post(_M.RELOAD_EVENT, ngx.req.get_method(), ngx.time()) + if not success then + core.response.exit(503, err) + end - return 200, "done" + core.response.exit(200, "done") end - return { -- /v1/schema { @@ -485,7 +488,7 @@ return { { methods = {"POST"}, uris = {"/plugins_reload"}, - handler = _M.plugins_reload, + handler = _M.post_reload_plugins, }, get_health_checkers = _get_health_checkers, } diff --git a/apisix/init.lua b/apisix/init.lua index 9a13fae8eb2a..91dc83f0b88e 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -155,6 +155,7 @@ function _M.http_init_worker() apisix_upstream.init_worker() require("apisix.plugins.ext-plugin.init").init_worker() + control_api_router.init_worker() local_conf = core.config.local_conf() if local_conf.apisix and local_conf.apisix.enable_server_tokens == false then From 083fd9879adef087b608d1ffb293392cbe2d8275 Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Tue, 6 Feb 2024 22:32:45 +0530 Subject: [PATCH 3/9] fix: add test cases Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/control/router.lua | 88 ++++++++- apisix/control/v1.lua | 6 +- t/control/plugins-reload.t | 395 +++++++++++++++++++++++++++++++++++-- 3 files changed, 469 insertions(+), 20 deletions(-) diff --git a/apisix/control/router.lua b/apisix/control/router.lua index 58418e4daa92..0552ed8d8030 100644 --- a/apisix/control/router.lua +++ b/apisix/control/router.lua @@ -27,6 +27,7 @@ local pairs = pairs local type = type local ngx = ngx local get_method = ngx.req.get_method +local ngx_worker_id = ngx.worker.id local events = require("apisix.events") local _M = {} @@ -46,6 +47,80 @@ local function format_dismod_uri(mod_name, uri) return core.table.concat(tmp, "") 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(reset) + local local_conf = core.config.local_conf() + + local plugins = {} + for _, name in ipairs(local_conf.plugins) do + core.table.insert(plugins, { + name = name, + }) + end + + for _, name in ipairs(local_conf.stream_plugins) do + core.table.insert(plugins, { + name = name, + stream = true, + }) + end + + if reset then + local res, err = core.etcd.get("/plugins") + if not res then + core.log.error("failed to get current plugins: ", err) + return + end + + if res.status == 404 then + -- nothing need to be reset + return + end + + if res.status ~= 200 then + core.log.error("failed to get current plugins, status: ", res.status) + return + end + + local stored_plugins = res.body.node.value + local revision = res.body.node.modifiedIndex + if plugins_eq(stored_plugins, plugins) then + core.log.info("plugins not changed, don't need to reset") + return + end + + core.log.warn("sync local conf to etcd") + + local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) + if not res then + core.log.error("failed to set plugins: ", err) + end + + return + end + + core.log.warn("sync local conf to etcd") + + -- 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 + core.log.error("failed to set plugins: ", err) + end +end + -- we do not hardcode the discovery module's control api uri local function format_dismod_control_api_uris(mod_name, api_route) if not api_route or #api_route == 0 then @@ -202,13 +277,22 @@ local function reload_plugins() core.log.info("start to hot reload plugins") plugin_mod.load() - return 200, "done" + local local_conf = core.config.local_conf() + local deployment_role = core.table.try_read_attr( + local_conf, "deployment", "role") + if deployment_role ~= "data_plane" then + -- data_plane should not write to etcd + if ngx_worker_id() == 0 then + sync_local_conf_to_etcd() + end + end + end function _M.init_worker() -- register reload plugin handler - events:register(reload_plugins, builtin_v1_routes.RELOAD_EVENT, "PUT") + events:register(reload_plugins, builtin_v1_routes.reload_event, "PUT") end return _M diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index feccfed27514..d29b9b7ba1ea 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -25,13 +25,14 @@ local collectgarbage = collectgarbage local ipairs = ipairs local pcall = pcall local str_format = string.format +local ngx = ngx local ngx_var = ngx.var local events = require("apisix.events") local _M = {} -_M.RELOAD_EVENT = "plugin-reload" +_M.RELOAD_EVENT = 'control-api-plugin-reload' function _M.schema() local http_plugins, stream_plugins = plugin.get_all({ @@ -486,9 +487,10 @@ return { }, -- /v1/plugins_reload { - methods = {"POST"}, + methods = {"PUT"}, uris = {"/plugins_reload"}, handler = _M.post_reload_plugins, }, get_health_checkers = _get_health_checkers, + reload_event = _M.RELOAD_EVENT, } diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t index 45523e9ca849..d367e9f44dff 100644 --- a/t/control/plugins-reload.t +++ b/t/control/plugins-reload.t @@ -21,32 +21,395 @@ no_long_string(); no_root_location(); no_shuffle(); log_level("info"); +workers(2); -our $yaml_config = <<_EOC_; +add_block_preprocessor(sub { + my ($block) = @_; + + $block; +}); + +run_tests; + +__DATA__ + +=== TEST 1: reload plugins +--- yaml_config apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin") + + local code, body, res = t.test('/v1/plugins_reload', + ngx.HTTP_PUT) + ngx.say(res) + ngx.sleep(1) + } +} +--- request +GET /t +--- response_body +done +--- grep_error_log eval +qr/sync local conf to etcd/ +--- grep_error_log_out +sync local conf to etcd +--- error_log +load plugin times: 2 +load plugin times: 2 +start to hot reload plugins +start to hot reload plugins + + + +=== TEST 2: reload plugins triggers plugin list sync +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + local config_util = require("apisix.core.config_util") + ngx.sleep(0.5) -- make sure the sync happened when admin starts is already finished + + local before_reload = true + local plugins_conf, err + plugins_conf, err = core.config.new("/plugins", { + automatic = true, + single_item = true, + filter = function(item) + -- called once before reload for sync data from admin + ngx.log(ngx.WARN, "reload plugins on node ", + before_reload and "before reload" or "after reload") + ngx.log(ngx.WARN, require("toolkit.json").encode(item.value)) + end, + }) + if not plugins_conf then + error("failed to create etcd instance for fetching /plugins : " + .. err) + end + ngx.sleep(0.5) + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - jwt-auth +stream_plugins: + - mqtt-proxy + ]] + require("lib.test_admin").set_config_yaml(data) + + before_reload = false + local t = require("lib.test_admin").test + local code, _, org_body = t('/v1/plugins_reload', + ngx.HTTP_PUT) + + ngx.status = code + ngx.say(org_body) + ngx.sleep(1) + } +} +--- request +GET /t +--- response_body +done +--- grep_error_log eval +qr/reload plugins on node \w+ reload/ +--- grep_error_log_out +reload plugins on node before reload +reload plugins on node after reload +--- error_log +filter(): [{"name":"jwt-auth"},{"name":"mqtt-proxy","stream":true}] + + + +=== TEST 3: reload plugins when attributes changed +--- yaml_config +apisix: node_listen: 1984 -_EOC_ + enable_admin: true + node_listen: 1984 +plugins: + - example-plugin +plugin_attr: + example-plugin: + val: 0 +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + ngx.sleep(0.1) + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - example-plugin +plugin_attr: + example-plugin: + val: 1 + ]] + require("lib.test_admin").set_config_yaml(data) + + local t = require("lib.test_admin").test + local code, _, org_body = t('/v1/plugins_reload', + ngx.HTTP_PUT) + + ngx.status = code + ngx.say(org_body) + ngx.sleep(0.1) + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 +plugins: + - example-plugin +plugin_attr: + example-plugin: + val: 1 + ]] + require("lib.test_admin").set_config_yaml(data) + + local t = require("lib.test_admin").test + local code, _, org_body = t('/v1/plugins_reload', + ngx.HTTP_PUT) + ngx.say(org_body) + ngx.sleep(0.1) + } +} +--- request +GET /t +--- response_body +done +done +--- grep_error_log eval +qr/example-plugin get plugin attr val: \d+/ +--- grep_error_log_out +example-plugin get plugin attr val: 0 +example-plugin get plugin attr val: 0 +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 +example-plugin get plugin attr val: 1 +example-plugin get plugin attr val: 1 +example-plugin get plugin attr val: 1 -run_tests(); -__DATA__ -=== TEST 1: test plugins-reload ---- yaml_config eval: $::yaml_config +=== TEST 4: reload plugins to change prometheus' export uri +--- yaml_config +apisix: + node_listen: 1984 +plugins: + - public-api + - prometheus +plugin_attr: + prometheus: + export_uri: /metrics +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + ngx.sleep(0.1) + local t = require("lib.test_admin").test + + -- setup public API route + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "public-api": {} + }, + "uri": "/apisix/metrics" + }]] + ) + ngx.say(code) + + local code, _, org_body = t('/apisix/metrics', + ngx.HTTP_GET) + ngx.say(code) + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - public-api + - prometheus +plugin_attr: + prometheus: + export_uri: /apisix/metrics + ]] + require("lib.test_admin").set_config_yaml(data) + + local code, _, org_body = t('/v1/plugins_reload', + ngx.HTTP_PUT) + + ngx.say(org_body) + + ngx.sleep(0.1) + local code, _, org_body = t('/apisix/metrics', + ngx.HTTP_GET) + ngx.say(code) + } +} +--- request +GET /t +--- response_body +201 +404 +done +200 + + + +=== TEST 5: reload plugins to disable skywalking +--- yaml_config +apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - skywalking +plugin_attr: + skywalking: + service_name: APISIX + service_instance_name: "APISIX Instance Name" + endpoint_addr: http://127.0.0.1:12801 + report_interval: 1 +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + ngx.sleep(1.2) + local t = require("lib.test_admin").test + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 +plugins: + - prometheus + ]] + require("lib.test_admin").set_config_yaml(data) + + local code, _, org_body = t('/v1/plugins_reload', + ngx.HTTP_PUT) + + ngx.say(org_body) + + ngx.sleep(2) + } +} +--- request +GET /t +--- response_body +done +--- no_error_log +[alert] +--- grep_error_log eval +qr/Instance report fails/ +--- grep_error_log_out +Instance report fails + + + +=== TEST 6: wrong method to reload plugins +--- request +GET /v1/plugins_reload +--- error_code: 404 + + + +=== TEST 7: wrong method to reload plugins +--- request +POST /v1/plugins_reload +--- error_code: 404 + + + +=== TEST 8: reload plugin with data_plane deployment +--- yaml_config +apisix: + node_listen: 1984 + enable_admin: false +deployment: + role: data_plane + role_data_plane: + config_provider: yaml +--- apisix_yaml +routes: + - + uri: /hello + upstream: + nodes: + "127.0.0.1:1980": 1 + type: roundrobin +#END --- config - location /t { - content_by_lua_block { - local json = require("toolkit.json") - local t = require("lib.test_admin") - - local code, body, res = t.test('/v1/plugins_reload', - ngx.HTTP_POST) - ngx.say(res) - } +location /t { + content_by_lua_block { + local t = require("lib.test_admin") + + local code, body, res = t.test('/v1/plugins_reload', + ngx.HTTP_PUT) + ngx.say(res) + ngx.sleep(1) } +} --- request GET /t ---- error_code: 200 --- response_body done +--- error_log +load plugin times: 2 +load plugin times: 2 +start to hot reload plugins +start to hot reload plugins \ No newline at end of file From 82598ee0e404f428efe78fde2445dd4fc0ff0ddc Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Tue, 6 Feb 2024 23:00:26 +0530 Subject: [PATCH 4/9] fix: eclint Signed-off-by: Mohammad Shehar Yaar Tausif --- t/control/plugins-reload.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t index d367e9f44dff..14b0ad124dd9 100644 --- a/t/control/plugins-reload.t +++ b/t/control/plugins-reload.t @@ -412,4 +412,4 @@ done load plugin times: 2 load plugin times: 2 start to hot reload plugins -start to hot reload plugins \ No newline at end of file +start to hot reload plugins From 05a8cf2dab51ba7ef28df564c0278b389bff948b Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Wed, 7 Feb 2024 12:20:25 +0530 Subject: [PATCH 5/9] fix: move common func to utils Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/admin/init.lua | 77 +--------------------------- apisix/control/router.lua | 74 +-------------------------- apisix/control/v1.lua | 4 +- apisix/utils/config_etcd.lua | 96 +++++++++++++++++++++++++++++++++++ docs/en/latest/control-api.md | 4 +- t/control/plugins-reload.t | 18 +++---- 6 files changed, 112 insertions(+), 161 deletions(-) create mode 100644 apisix/utils/config_etcd.lua diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua index 9596a8d62e87..4b29d496dab7 100644 --- a/apisix/admin/init.lua +++ b/apisix/admin/init.lua @@ -33,6 +33,7 @@ local reload_event = "/apisix/admin/plugins/reload" local ipairs = ipairs local error = error local type = type +local sync_local_conf_to_etcd = require("apisix.utils.config_etcd").sync_local_conf_to_etcd local events @@ -290,82 +291,6 @@ 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(reset) - local local_conf = core.config.local_conf() - - local plugins = {} - for _, name in ipairs(local_conf.plugins) do - core.table.insert(plugins, { - name = name, - }) - end - - for _, name in ipairs(local_conf.stream_plugins) do - core.table.insert(plugins, { - name = name, - stream = true, - }) - end - - if reset then - local res, err = core.etcd.get("/plugins") - if not res then - core.log.error("failed to get current plugins: ", err) - return - end - - if res.status == 404 then - -- nothing need to be reset - return - end - - if res.status ~= 200 then - core.log.error("failed to get current plugins, status: ", res.status) - return - end - - local stored_plugins = res.body.node.value - local revision = res.body.node.modifiedIndex - if plugins_eq(stored_plugins, plugins) then - core.log.info("plugins not changed, don't need to reset") - return - end - - core.log.warn("sync local conf to etcd") - - local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) - if not res then - core.log.error("failed to set plugins: ", err) - end - - return - end - - core.log.warn("sync local conf to etcd") - - -- 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 - core.log.error("failed to set plugins: ", err) - end -end - - local function reload_plugins(data, event, source, pid) core.log.info("start to hot reload plugins") plugin.load() diff --git a/apisix/control/router.lua b/apisix/control/router.lua index 0552ed8d8030..82ca28b5d943 100644 --- a/apisix/control/router.lua +++ b/apisix/control/router.lua @@ -29,6 +29,7 @@ local ngx = ngx local get_method = ngx.req.get_method local ngx_worker_id = ngx.worker.id local events = require("apisix.events") +local sync_local_conf_to_etcd = require("apisix.utils.config_etcd").sync_local_conf_to_etcd local _M = {} @@ -47,79 +48,6 @@ local function format_dismod_uri(mod_name, uri) return core.table.concat(tmp, "") 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(reset) - local local_conf = core.config.local_conf() - - local plugins = {} - for _, name in ipairs(local_conf.plugins) do - core.table.insert(plugins, { - name = name, - }) - end - - for _, name in ipairs(local_conf.stream_plugins) do - core.table.insert(plugins, { - name = name, - stream = true, - }) - end - - if reset then - local res, err = core.etcd.get("/plugins") - if not res then - core.log.error("failed to get current plugins: ", err) - return - end - - if res.status == 404 then - -- nothing need to be reset - return - end - - if res.status ~= 200 then - core.log.error("failed to get current plugins, status: ", res.status) - return - end - - local stored_plugins = res.body.node.value - local revision = res.body.node.modifiedIndex - if plugins_eq(stored_plugins, plugins) then - core.log.info("plugins not changed, don't need to reset") - return - end - - core.log.warn("sync local conf to etcd") - - local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) - if not res then - core.log.error("failed to set plugins: ", err) - end - - return - end - - core.log.warn("sync local conf to etcd") - - -- 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 - core.log.error("failed to set plugins: ", err) - end -end -- we do not hardcode the discovery module's control api uri local function format_dismod_control_api_uris(mod_name, api_route) diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index d29b9b7ba1ea..213ed0ac46b8 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -485,10 +485,10 @@ return { uris = {"/plugin_metadata/*"}, handler = _M.dump_plugin_metadata, }, - -- /v1/plugins_reload + -- /v1/plugins/reload { methods = {"PUT"}, - uris = {"/plugins_reload"}, + uris = {"/plugins/reload"}, handler = _M.post_reload_plugins, }, get_health_checkers = _get_health_checkers, diff --git a/apisix/utils/config_etcd.lua b/apisix/utils/config_etcd.lua new file mode 100644 index 000000000000..53b2683f70ae --- /dev/null +++ b/apisix/utils/config_etcd.lua @@ -0,0 +1,96 @@ +-- +-- 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 core = require("apisix.core") + +local _M = {} + +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 + + +function _M.sync_local_conf_to_etcd(reset) + local local_conf = core.config.local_conf() + + local plugins = {} + for _, name in ipairs(local_conf.plugins) do + core.table.insert(plugins, { + name = name, + }) + end + + for _, name in ipairs(local_conf.stream_plugins) do + core.table.insert(plugins, { + name = name, + stream = true, + }) + end + + if reset then + local res, err = core.etcd.get("/plugins") + if not res then + core.log.error("failed to get current plugins: ", err) + return + end + + if res.status == 404 then + -- nothing need to be reset + return + end + + if res.status ~= 200 then + core.log.error("failed to get current plugins, status: ", res.status) + return + end + + local stored_plugins = res.body.node.value + local revision = res.body.node.modifiedIndex + if plugins_eq(stored_plugins, plugins) then + core.log.info("plugins not changed, don't need to reset") + return + end + + core.log.warn("sync local conf to etcd") + + local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) + if not res then + core.log.error("failed to set plugins: ", err) + end + + return + end + + core.log.warn("sync local conf to etcd") + + -- 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 + core.log.error("failed to set plugins: ", err) + end +end + +return _M diff --git a/docs/en/latest/control-api.md b/docs/en/latest/control-api.md index c6b23ffbc67f..1985ce72648a 100644 --- a/docs/en/latest/control-api.md +++ b/docs/en/latest/control-api.md @@ -476,8 +476,10 @@ Dumps the metadata with the specified `plugin_name`: } ``` -### POST /v1/plugins_reload +### PUT /v1/plugins/reload Introduced in [v3.9.0](https://github.com/apache/apisix/releases/tag/3.9.0) Triggers a hot reload of the plugins. + +```shell diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t index 14b0ad124dd9..d9a1a74498e6 100644 --- a/t/control/plugins-reload.t +++ b/t/control/plugins-reload.t @@ -46,7 +46,7 @@ location /t { content_by_lua_block { local t = require("lib.test_admin") - local code, body, res = t.test('/v1/plugins_reload', + local code, body, res = t.test('/v1/plugins/reload', ngx.HTTP_PUT) ngx.say(res) ngx.sleep(1) @@ -116,7 +116,7 @@ stream_plugins: before_reload = false local t = require("lib.test_admin").test - local code, _, org_body = t('/v1/plugins_reload', + local code, _, org_body = t('/v1/plugins/reload', ngx.HTTP_PUT) ngx.status = code @@ -176,7 +176,7 @@ plugin_attr: require("lib.test_admin").set_config_yaml(data) local t = require("lib.test_admin").test - local code, _, org_body = t('/v1/plugins_reload', + local code, _, org_body = t('/v1/plugins/reload', ngx.HTTP_PUT) ngx.status = code @@ -201,7 +201,7 @@ plugin_attr: require("lib.test_admin").set_config_yaml(data) local t = require("lib.test_admin").test - local code, _, org_body = t('/v1/plugins_reload', + local code, _, org_body = t('/v1/plugins/reload', ngx.HTTP_PUT) ngx.say(org_body) ngx.sleep(0.1) @@ -282,7 +282,7 @@ plugin_attr: ]] require("lib.test_admin").set_config_yaml(data) - local code, _, org_body = t('/v1/plugins_reload', + local code, _, org_body = t('/v1/plugins/reload', ngx.HTTP_PUT) ngx.say(org_body) @@ -340,7 +340,7 @@ plugins: ]] require("lib.test_admin").set_config_yaml(data) - local code, _, org_body = t('/v1/plugins_reload', + local code, _, org_body = t('/v1/plugins/reload', ngx.HTTP_PUT) ngx.say(org_body) @@ -363,14 +363,14 @@ Instance report fails === TEST 6: wrong method to reload plugins --- request -GET /v1/plugins_reload +GET /v1/plugins/reload --- error_code: 404 === TEST 7: wrong method to reload plugins --- request -POST /v1/plugins_reload +POST /v1/plugins/reload --- error_code: 404 @@ -398,7 +398,7 @@ location /t { content_by_lua_block { local t = require("lib.test_admin") - local code, body, res = t.test('/v1/plugins_reload', + local code, body, res = t.test('/v1/plugins/reload', ngx.HTTP_PUT) ngx.say(res) ngx.sleep(1) From d8ba5a2e508ef19c229e7bcb14d40cfb8c68f6fd Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Wed, 7 Feb 2024 12:22:17 +0530 Subject: [PATCH 6/9] fix: add usage Signed-off-by: Mohammad Shehar Yaar Tausif --- docs/en/latest/control-api.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/latest/control-api.md b/docs/en/latest/control-api.md index 1985ce72648a..8bd147869479 100644 --- a/docs/en/latest/control-api.md +++ b/docs/en/latest/control-api.md @@ -483,3 +483,5 @@ Introduced in [v3.9.0](https://github.com/apache/apisix/releases/tag/3.9.0) Triggers a hot reload of the plugins. ```shell +curl "http://127.0.0.1:9090/v1/plugins/reload" -X PUT +``` From 643cd6d0dd50a8ea115d87754f1a101ad54ca8c2 Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Wed, 7 Feb 2024 12:54:07 +0530 Subject: [PATCH 7/9] fix: code lint Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/utils/config_etcd.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/apisix/utils/config_etcd.lua b/apisix/utils/config_etcd.lua index 53b2683f70ae..16c714dc544a 100644 --- a/apisix/utils/config_etcd.lua +++ b/apisix/utils/config_etcd.lua @@ -15,6 +15,7 @@ -- limitations under the License. -- local core = require("apisix.core") +local ipairs = ipairs local _M = {} From f3934ee6b2f1ca0ed69b50c7d5e6a36ab45fe819 Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Sun, 18 Feb 2024 12:35:05 +0530 Subject: [PATCH 8/9] fix: revert sync Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/admin/init.lua | 77 +++++++++++- apisix/control/router.lua | 26 ---- apisix/control/v1.lua | 13 +- apisix/init.lua | 1 - apisix/utils/config_etcd.lua | 97 --------------- t/control/plugins-reload.t | 226 +---------------------------------- 6 files changed, 85 insertions(+), 355 deletions(-) delete mode 100644 apisix/utils/config_etcd.lua diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua index 4b29d496dab7..9596a8d62e87 100644 --- a/apisix/admin/init.lua +++ b/apisix/admin/init.lua @@ -33,7 +33,6 @@ local reload_event = "/apisix/admin/plugins/reload" local ipairs = ipairs local error = error local type = type -local sync_local_conf_to_etcd = require("apisix.utils.config_etcd").sync_local_conf_to_etcd local events @@ -291,6 +290,82 @@ 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(reset) + local local_conf = core.config.local_conf() + + local plugins = {} + for _, name in ipairs(local_conf.plugins) do + core.table.insert(plugins, { + name = name, + }) + end + + for _, name in ipairs(local_conf.stream_plugins) do + core.table.insert(plugins, { + name = name, + stream = true, + }) + end + + if reset then + local res, err = core.etcd.get("/plugins") + if not res then + core.log.error("failed to get current plugins: ", err) + return + end + + if res.status == 404 then + -- nothing need to be reset + return + end + + if res.status ~= 200 then + core.log.error("failed to get current plugins, status: ", res.status) + return + end + + local stored_plugins = res.body.node.value + local revision = res.body.node.modifiedIndex + if plugins_eq(stored_plugins, plugins) then + core.log.info("plugins not changed, don't need to reset") + return + end + + core.log.warn("sync local conf to etcd") + + local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) + if not res then + core.log.error("failed to set plugins: ", err) + end + + return + end + + core.log.warn("sync local conf to etcd") + + -- 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 + core.log.error("failed to set plugins: ", err) + end +end + + local function reload_plugins(data, event, source, pid) core.log.info("start to hot reload plugins") plugin.load() diff --git a/apisix/control/router.lua b/apisix/control/router.lua index 82ca28b5d943..13081721baba 100644 --- a/apisix/control/router.lua +++ b/apisix/control/router.lua @@ -27,9 +27,6 @@ local pairs = pairs local type = type local ngx = ngx local get_method = ngx.req.get_method -local ngx_worker_id = ngx.worker.id -local events = require("apisix.events") -local sync_local_conf_to_etcd = require("apisix.utils.config_etcd").sync_local_conf_to_etcd local _M = {} @@ -48,7 +45,6 @@ local function format_dismod_uri(mod_name, uri) return core.table.concat(tmp, "") end - -- we do not hardcode the discovery module's control api uri local function format_dismod_control_api_uris(mod_name, api_route) if not api_route or #api_route == 0 then @@ -201,26 +197,4 @@ end end -- do -local function reload_plugins() - core.log.info("start to hot reload plugins") - plugin_mod.load() - - local local_conf = core.config.local_conf() - local deployment_role = core.table.try_read_attr( - local_conf, "deployment", "role") - if deployment_role ~= "data_plane" then - -- data_plane should not write to etcd - if ngx_worker_id() == 0 then - sync_local_conf_to_etcd() - end - end - -end - - -function _M.init_worker() - -- register reload plugin handler - events:register(reload_plugins, builtin_v1_routes.reload_event, "PUT") -end - return _M diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index 213ed0ac46b8..135d1490554a 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -403,13 +403,11 @@ function _M.dump_plugin_metadata() return 200, metadata.value end -function _M.post_reload_plugins() - local success, err = events:post(_M.RELOAD_EVENT, ngx.req.get_method(), ngx.time()) - if not success then - core.response.exit(503, err) - end +function _M.reload_plugins() + core.log.info("start to hot reload plugins") + plugin.load() - core.response.exit(200, "done") + return 200, "done" end return { @@ -489,8 +487,7 @@ return { { methods = {"PUT"}, uris = {"/plugins/reload"}, - handler = _M.post_reload_plugins, + handler = _M.reload_plugins, }, get_health_checkers = _get_health_checkers, - reload_event = _M.RELOAD_EVENT, } diff --git a/apisix/init.lua b/apisix/init.lua index 91dc83f0b88e..9a13fae8eb2a 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -155,7 +155,6 @@ function _M.http_init_worker() apisix_upstream.init_worker() require("apisix.plugins.ext-plugin.init").init_worker() - control_api_router.init_worker() local_conf = core.config.local_conf() if local_conf.apisix and local_conf.apisix.enable_server_tokens == false then diff --git a/apisix/utils/config_etcd.lua b/apisix/utils/config_etcd.lua deleted file mode 100644 index 16c714dc544a..000000000000 --- a/apisix/utils/config_etcd.lua +++ /dev/null @@ -1,97 +0,0 @@ --- --- 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 core = require("apisix.core") -local ipairs = ipairs - -local _M = {} - -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 - - -function _M.sync_local_conf_to_etcd(reset) - local local_conf = core.config.local_conf() - - local plugins = {} - for _, name in ipairs(local_conf.plugins) do - core.table.insert(plugins, { - name = name, - }) - end - - for _, name in ipairs(local_conf.stream_plugins) do - core.table.insert(plugins, { - name = name, - stream = true, - }) - end - - if reset then - local res, err = core.etcd.get("/plugins") - if not res then - core.log.error("failed to get current plugins: ", err) - return - end - - if res.status == 404 then - -- nothing need to be reset - return - end - - if res.status ~= 200 then - core.log.error("failed to get current plugins, status: ", res.status) - return - end - - local stored_plugins = res.body.node.value - local revision = res.body.node.modifiedIndex - if plugins_eq(stored_plugins, plugins) then - core.log.info("plugins not changed, don't need to reset") - return - end - - core.log.warn("sync local conf to etcd") - - local res, err = core.etcd.atomic_set("/plugins", plugins, nil, revision) - if not res then - core.log.error("failed to set plugins: ", err) - end - - return - end - - core.log.warn("sync local conf to etcd") - - -- 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 - core.log.error("failed to set plugins: ", err) - end -end - -return _M diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t index d9a1a74498e6..d9a9eb32e972 100644 --- a/t/control/plugins-reload.t +++ b/t/control/plugins-reload.t @@ -56,89 +56,12 @@ location /t { GET /t --- response_body done ---- grep_error_log eval -qr/sync local conf to etcd/ ---- grep_error_log_out -sync local conf to etcd --- error_log -load plugin times: 2 -load plugin times: 2 -start to hot reload plugins start to hot reload plugins -=== TEST 2: reload plugins triggers plugin list sync ---- config -location /t { - content_by_lua_block { - local core = require "apisix.core" - local config_util = require("apisix.core.config_util") - ngx.sleep(0.5) -- make sure the sync happened when admin starts is already finished - - local before_reload = true - local plugins_conf, err - plugins_conf, err = core.config.new("/plugins", { - automatic = true, - single_item = true, - filter = function(item) - -- called once before reload for sync data from admin - ngx.log(ngx.WARN, "reload plugins on node ", - before_reload and "before reload" or "after reload") - ngx.log(ngx.WARN, require("toolkit.json").encode(item.value)) - end, - }) - if not plugins_conf then - error("failed to create etcd instance for fetching /plugins : " - .. err) - end - ngx.sleep(0.5) - - local data = [[ -deployment: - role: traditional - role_traditional: - config_provider: etcd - admin: - admin_key: null -apisix: - node_listen: 1984 - enable_control: true - control: - ip: "127.0.0.1" - port: 9090 -plugins: - - jwt-auth -stream_plugins: - - mqtt-proxy - ]] - require("lib.test_admin").set_config_yaml(data) - - before_reload = false - local t = require("lib.test_admin").test - local code, _, org_body = t('/v1/plugins/reload', - ngx.HTTP_PUT) - - ngx.status = code - ngx.say(org_body) - ngx.sleep(1) - } -} ---- request -GET /t ---- response_body -done ---- grep_error_log eval -qr/reload plugins on node \w+ reload/ ---- grep_error_log_out -reload plugins on node before reload -reload plugins on node after reload ---- error_log -filter(): [{"name":"jwt-auth"},{"name":"mqtt-proxy","stream":true}] - - - -=== TEST 3: reload plugins when attributes changed +=== TEST 2: reload plugins when attributes changed --- yaml_config apisix: node_listen: 1984 @@ -220,162 +143,24 @@ example-plugin get plugin attr val: 0 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 -example-plugin get plugin attr val: 1 -example-plugin get plugin attr val: 1 -example-plugin get plugin attr val: 1 -=== TEST 4: reload plugins to change prometheus' export uri ---- yaml_config -apisix: - node_listen: 1984 -plugins: - - public-api - - prometheus -plugin_attr: - prometheus: - export_uri: /metrics ---- config -location /t { - content_by_lua_block { - local core = require "apisix.core" - ngx.sleep(0.1) - local t = require("lib.test_admin").test - - -- setup public API route - local code, body = t('/apisix/admin/routes/1', - ngx.HTTP_PUT, - [[{ - "plugins": { - "public-api": {} - }, - "uri": "/apisix/metrics" - }]] - ) - ngx.say(code) - - local code, _, org_body = t('/apisix/metrics', - ngx.HTTP_GET) - ngx.say(code) - - local data = [[ -deployment: - role: traditional - role_traditional: - config_provider: etcd - admin: - admin_key: null -apisix: - node_listen: 1984 - enable_control: true - control: - ip: "127.0.0.1" - port: 9090 -plugins: - - public-api - - prometheus -plugin_attr: - prometheus: - export_uri: /apisix/metrics - ]] - require("lib.test_admin").set_config_yaml(data) - - local code, _, org_body = t('/v1/plugins/reload', - ngx.HTTP_PUT) - - ngx.say(org_body) - - ngx.sleep(0.1) - local code, _, org_body = t('/apisix/metrics', - ngx.HTTP_GET) - ngx.say(code) - } -} ---- request -GET /t ---- response_body -201 -404 -done -200 - - - -=== TEST 5: reload plugins to disable skywalking ---- yaml_config -apisix: - node_listen: 1984 - enable_control: true - control: - ip: "127.0.0.1" - port: 9090 -plugins: - - skywalking -plugin_attr: - skywalking: - service_name: APISIX - service_instance_name: "APISIX Instance Name" - endpoint_addr: http://127.0.0.1:12801 - report_interval: 1 ---- config -location /t { - content_by_lua_block { - local core = require "apisix.core" - ngx.sleep(1.2) - local t = require("lib.test_admin").test - - local data = [[ -deployment: - role: traditional - role_traditional: - config_provider: etcd - admin: - admin_key: null -apisix: - node_listen: 1984 -plugins: - - prometheus - ]] - require("lib.test_admin").set_config_yaml(data) - - local code, _, org_body = t('/v1/plugins/reload', - ngx.HTTP_PUT) - - ngx.say(org_body) - - ngx.sleep(2) - } -} ---- request -GET /t ---- response_body -done ---- no_error_log -[alert] ---- grep_error_log eval -qr/Instance report fails/ ---- grep_error_log_out -Instance report fails - - - -=== TEST 6: wrong method to reload plugins +=== TEST 3: wrong method to reload plugins --- request GET /v1/plugins/reload --- error_code: 404 -=== TEST 7: wrong method to reload plugins +=== TEST 4: wrong method to reload plugins --- request POST /v1/plugins/reload --- error_code: 404 -=== TEST 8: reload plugin with data_plane deployment +=== TEST 5: reload plugin with data_plane deployment --- yaml_config apisix: node_listen: 1984 @@ -409,7 +194,4 @@ GET /t --- response_body done --- error_log -load plugin times: 2 -load plugin times: 2 -start to hot reload plugins start to hot reload plugins From 92808d117e1ea079da078089eec16f53d2c919e3 Mon Sep 17 00:00:00 2001 From: Mohammad Shehar Yaar Tausif Date: Sun, 18 Feb 2024 14:01:16 +0530 Subject: [PATCH 9/9] fix: add events Signed-off-by: Mohammad Shehar Yaar Tausif --- apisix/control/router.lua | 12 +++ apisix/control/v1.lua | 13 ++-- apisix/init.lua | 1 + t/control/plugins-reload.t | 150 ++++++++++++++++++++++++++++++++++++- 4 files changed, 168 insertions(+), 8 deletions(-) diff --git a/apisix/control/router.lua b/apisix/control/router.lua index 13081721baba..e6e5ff9b3b0e 100644 --- a/apisix/control/router.lua +++ b/apisix/control/router.lua @@ -27,6 +27,7 @@ local pairs = pairs local type = type local ngx = ngx local get_method = ngx.req.get_method +local events = require("apisix.events") local _M = {} @@ -197,4 +198,15 @@ end end -- do +local function reload_plugins() + core.log.info("start to hot reload plugins") + plugin_mod.load() +end + + +function _M.init_worker() + -- register reload plugin handler + events:register(reload_plugins, builtin_v1_routes.reload_event, "PUT") +end + return _M diff --git a/apisix/control/v1.lua b/apisix/control/v1.lua index 135d1490554a..213ed0ac46b8 100644 --- a/apisix/control/v1.lua +++ b/apisix/control/v1.lua @@ -403,11 +403,13 @@ function _M.dump_plugin_metadata() return 200, metadata.value end -function _M.reload_plugins() - core.log.info("start to hot reload plugins") - plugin.load() +function _M.post_reload_plugins() + local success, err = events:post(_M.RELOAD_EVENT, ngx.req.get_method(), ngx.time()) + if not success then + core.response.exit(503, err) + end - return 200, "done" + core.response.exit(200, "done") end return { @@ -487,7 +489,8 @@ return { { methods = {"PUT"}, uris = {"/plugins/reload"}, - handler = _M.reload_plugins, + handler = _M.post_reload_plugins, }, get_health_checkers = _get_health_checkers, + reload_event = _M.RELOAD_EVENT, } diff --git a/apisix/init.lua b/apisix/init.lua index 9a13fae8eb2a..91dc83f0b88e 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -155,6 +155,7 @@ function _M.http_init_worker() apisix_upstream.init_worker() require("apisix.plugins.ext-plugin.init").init_worker() + control_api_router.init_worker() local_conf = core.config.local_conf() if local_conf.apisix and local_conf.apisix.enable_server_tokens == false then diff --git a/t/control/plugins-reload.t b/t/control/plugins-reload.t index d9a9eb32e972..cb9e1862331e 100644 --- a/t/control/plugins-reload.t +++ b/t/control/plugins-reload.t @@ -57,6 +57,9 @@ GET /t --- response_body done --- error_log +load plugin times: 2 +load plugin times: 2 +start to hot reload plugins start to hot reload plugins @@ -143,24 +146,162 @@ example-plugin get plugin attr val: 0 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 +example-plugin get plugin attr val: 1 +example-plugin get plugin attr val: 1 +example-plugin get plugin attr val: 1 -=== TEST 3: wrong method to reload plugins +=== TEST 3: reload plugins to change prometheus' export uri +--- yaml_config +apisix: + node_listen: 1984 +plugins: + - public-api + - prometheus +plugin_attr: + prometheus: + export_uri: /metrics +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + ngx.sleep(0.1) + local t = require("lib.test_admin").test + + -- setup public API route + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "public-api": {} + }, + "uri": "/apisix/metrics" + }]] + ) + ngx.say(code) + + local code, _, org_body = t('/apisix/metrics', + ngx.HTTP_GET) + ngx.say(code) + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - public-api + - prometheus +plugin_attr: + prometheus: + export_uri: /apisix/metrics + ]] + require("lib.test_admin").set_config_yaml(data) + + local code, _, org_body = t('/v1/plugins/reload', + ngx.HTTP_PUT) + + ngx.say(org_body) + + ngx.sleep(0.1) + local code, _, org_body = t('/apisix/metrics', + ngx.HTTP_GET) + ngx.say(code) + } +} +--- request +GET /t +--- response_body +201 +404 +done +200 + + + +=== TEST 4: reload plugins to disable skywalking +--- yaml_config +apisix: + node_listen: 1984 + enable_control: true + control: + ip: "127.0.0.1" + port: 9090 +plugins: + - skywalking +plugin_attr: + skywalking: + service_name: APISIX + service_instance_name: "APISIX Instance Name" + endpoint_addr: http://127.0.0.1:12801 + report_interval: 1 +--- config +location /t { + content_by_lua_block { + local core = require "apisix.core" + ngx.sleep(1.2) + local t = require("lib.test_admin").test + + local data = [[ +deployment: + role: traditional + role_traditional: + config_provider: etcd + admin: + admin_key: null +apisix: + node_listen: 1984 +plugins: + - prometheus + ]] + require("lib.test_admin").set_config_yaml(data) + + local code, _, org_body = t('/v1/plugins/reload', + ngx.HTTP_PUT) + + ngx.say(org_body) + + ngx.sleep(2) + } +} +--- request +GET /t +--- response_body +done +--- no_error_log +[alert] +--- grep_error_log eval +qr/Instance report fails/ +--- grep_error_log_out +Instance report fails + + + +=== TEST 5: wrong method to reload plugins --- request GET /v1/plugins/reload --- error_code: 404 -=== TEST 4: wrong method to reload plugins +=== TEST 6: wrong method to reload plugins --- request POST /v1/plugins/reload --- error_code: 404 -=== TEST 5: reload plugin with data_plane deployment +=== TEST 7: reload plugin with data_plane deployment --- yaml_config apisix: node_listen: 1984 @@ -194,4 +335,7 @@ GET /t --- response_body done --- error_log +load plugin times: 2 +load plugin times: 2 +start to hot reload plugins start to hot reload plugins