Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add 'drain' CLI command to set /status/ready to 503 #13838

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions bin/kong
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ local cmds = {
roar = true,
hybrid = true,
vault = true,
drain = true,
}

-- unnecessary to inject nginx directives for these simple cmds
Expand All @@ -42,6 +43,7 @@ local skip_inject_cmds = {
quit = true,
health = true,
hybrid = true,
drain = true,
}

for k in pairs(cmds) do
Expand Down
3 changes: 3 additions & 0 deletions changelog/unreleased/kong/feat-kong-drain-cmd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
message: Add the `kong drain` CLI command to make the `/status/ready` endpoint return `503 Service Unavailable` response.
type: feature
scope: CLI Command
1 change: 1 addition & 0 deletions kong-3.9.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ build = {
["kong.cmd.vault"] = "kong/cmd/vault.lua",
["kong.cmd.version"] = "kong/cmd/version.lua",
["kong.cmd.hybrid"] = "kong/cmd/hybrid.lua",
["kong.cmd.drain"] = "kong/cmd/drain.lua",
["kong.cmd.utils.log"] = "kong/cmd/utils/log.lua",
["kong.cmd.utils.kill"] = "kong/cmd/utils/kill.lua",
["kong.cmd.utils.env"] = "kong/cmd/utils/env.lua",
Expand Down
88 changes: 88 additions & 0 deletions kong/cmd/drain.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
local http = require "resty.luasocket.http"
local print = print
local fmt = string.format

local conf_loader = require "kong.conf_loader"
local pl_path = require "pl.path"
local log = require "kong.cmd.utils.log"
local json_encode = require("cjson.safe").encode

local function execute(args)
log.disable()

-- only to retrieve the default prefix or use given one
local conf = assert(conf_loader(args.conf, {
prefix = args.prefix
}))

if pl_path.exists(conf.kong_env) then
-- load <PREFIX>/kong.conf containing running node's config
conf = assert(conf_loader(conf.kong_env))
end

log.enable()

if #conf.status_listeners == 0 then
print("No status listeners found in configuration.")
return
end

local status_listener = conf.status_listeners[1]

local scheme = "http"
if status_listener.ssl then
scheme = "https"
end

local url = scheme .. "://" .. status_listener.ip .. ":" .. status_listener.port .. "/status/ready"

local httpc = http.new()
httpc:set_timeout(1000)


local res, err = httpc:request_uri(url, {
method = "POST",
headers = {
["Content-Type"] = "application/json"
},
body = json_encode({
status = "draining"
}),
-- we don't need to verify the SSL certificate for this request
ssl_verify = false,
})

httpc:close()

if not res then
print(fmt("Failed to send request to %s: %s", url, err))
return
end

if res.status ~= 204 then
print(fmt("Unexpected response status from %s: %d", url, res.status))
return
end

print("Kong's status successfully changed to 'draining'")
end


local lapp = [[
Usage: kong drain [OPTIONS]

Make status listeners(`/status/ready`) return 503 Service Unavailable.

Example usage:
kong drain

Options:
-c,--conf (optional string) configuration file
-p,--prefix (optional string) override prefix directory
]]


return {
lapp = lapp,
execute = execute,
}
27 changes: 23 additions & 4 deletions kong/status/ready.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ local PLUGINS_REBUILD_COUNTER_KEY = constants.PLUGINS_REBUILD_COUNTER_KEY
local ROUTERS_REBUILD_COUNTER_KEY = constants.ROUTERS_REBUILD_COUNTER_KEY
local DECLARATIVE_EMPTY_CONFIG_HASH = constants.DECLARATIVE_EMPTY_CONFIG_HASH

local KONG_STATUS_READY = "kong:status:ready"

local function is_dbless_ready(router_rebuilds, plugins_iterator_rebuilds)
if router_rebuilds < worker_count then
Expand Down Expand Up @@ -75,16 +76,16 @@ local function is_ready()
if not ok then
return false, "failed to connect to database"
end

kong.db:close()

if is_control_plane then
return true
end

local router_rebuilds =
local router_rebuilds =
tonumber(kong_shm:get(ROUTERS_REBUILD_COUNTER_KEY)) or 0
local plugins_iterator_rebuilds =
local plugins_iterator_rebuilds =
tonumber(kong_shm:get(PLUGINS_REBUILD_COUNTER_KEY)) or 0

local err
Expand All @@ -102,6 +103,15 @@ end
return {
["/status/ready"] = {
GET = function(self, dao, helpers)
local ready = kong_shm:get(KONG_STATUS_READY)
if ready == nil then
kong_shm:set(KONG_STATUS_READY, true)
end

if ready == false then
return kong.response.exit(503, { message = "draining" })
end

local ok, err = is_ready()
if ok then
ngx_log(ngx_DEBUG, "ready for proxying")
Expand All @@ -111,6 +121,15 @@ return {
ngx_log(ngx_NOTICE, "not ready for proxying: ", err)
return kong.response.exit(503, { message = err })
end
end,

POST = function(self, dao, helpers)
if self.params and self.params.status == "draining" then
kong_shm:set(KONG_STATUS_READY, false)
return kong.response.exit(204)
end

return kong.response.exit(400)
end
}
},
}
Loading
Loading