Skip to content

Commit

Permalink
feat: add configuration_hash in /status in dbless (#8214)
Browse files Browse the repository at this point in the history
* feat: add configuration_hash in dbless /status

* Update spec/02-integration/08-status_api/01-core_routes_spec.lua

Co-authored-by: Harry <harrybagdi@gmail.com>

* Update spec/02-integration/08-status_api/01-core_routes_spec.lua

Co-authored-by: Harry <harrybagdi@gmail.com>

* Update spec/02-integration/08-status_api/01-core_routes_spec.lua

Co-authored-by: Harry <harrybagdi@gmail.com>

* test(kong_routes) some syntax fixes

Co-authored-by: Harry <harrybagdi@gmail.com>
Co-authored-by: Vinicius Mignot <vinicius.mignot@gmail.com>
  • Loading branch information
3 people authored Feb 10, 2022
1 parent d12991f commit 4f8c99d
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 2 deletions.
12 changes: 12 additions & 0 deletions kong/api/routes/health.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local utils = require "kong.tools.utils"
local declarative = require "kong.db.declarative"

local find = string.find
local select = select
Expand All @@ -11,6 +12,8 @@ local knode = (kong and kong.node) and kong.node or
local select = select
local tonumber = tonumber
local kong = kong
local dbless = kong.configuration.database == "off"
local data_plane_role = kong.configuration.role == "data_plane"


return {
Expand Down Expand Up @@ -64,6 +67,15 @@ return {
},
}

-- if dbless mode is enabled we provide the current hash of the
-- data-plane in the status response as this enables control planes
-- to make decisions when something changes in the data-plane (e.g.
-- if the gateway gets unexpectedly restarted and its configuration
-- has been reset to empty).
if dbless or data_plane_role then
status_response.configuration_hash = declarative.get_current_hash()
end

-- TODO: no way to bypass connection pool
local ok, err = kong.db:connect()
if not ok then
Expand Down
11 changes: 10 additions & 1 deletion kong/db/declarative/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ local DECLARATIVE_LOCK_KEY = "declarative:lock"
local DECLARATIVE_LOCK_TTL = 60
local GLOBAL_QUERY_OPTS = { nulls = true, workspace = null }

local EMPTY_CONFIGURATION_HASH = string.rep("0", 32)


local declarative = {}

Expand Down Expand Up @@ -845,7 +847,14 @@ function declarative.load_into_cache(entities, meta, hash, shadow)
return nil, err
end

local ok, err = ngx.shared.kong:safe_set(DECLARATIVE_HASH_KEY, hash or true)
-- mask any default hash to indicate no hash is available.
if hash == EMPTY_CONFIGURATION_HASH or hash == "" then
hash = null
end

-- set the value of the configuration hash. The value can be nil, which
-- indicates that no configuration has been applied yet to the Gateway.
local ok, err = ngx.shared.kong:safe_set(DECLARATIVE_HASH_KEY, hash)
if not ok then
return nil, "failed to set " .. DECLARATIVE_HASH_KEY .. " in shm: " .. err
end
Expand Down
42 changes: 42 additions & 0 deletions spec/02-integration/04-admin_api/02-kong_routes_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe("Admin API - Kong routes with strategy #" .. strategy, function()
lazy_setup(function()
helpers.get_db_utils(nil, {}) -- runs migrations
assert(helpers.start_kong {
database = strategy,
plugins = "bundled,reports-api",
pg_password = "hide_me"
})
Expand Down Expand Up @@ -206,6 +207,47 @@ describe("Admin API - Kong routes with strategy #" .. strategy, function()
assert.is_number(json.server.connections_writing)
assert.is_number(json.server.connections_waiting)
assert.is_number(json.server.total_requests)
assert.is_nil(json.server.configuration_hash) -- not present in DB mode, or in DBLESS mode until configuration is applied
end)

it("returns status info including a configuration_hash in DBLESS mode if an initial configuration has been provided #off", function()
-- push an initial configuration so that a configuration_hash will be present
local postres = assert(client:send {
method = "POST",
path = "/config",
body = {
config = [[
_format_version: "1.1"
services:
- host: "konghq.com"
]],
},
headers = {
["Content-Type"] = "application/json"
}
})
assert.res_status(201, postres)

-- verify the status endpoint now includes a value (other than the default) for the configuration_hash
local res = assert(client:send {
method = "GET",
path = "/status"
})
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.is_table(json.database)
assert.is_table(json.server)
assert.is_boolean(json.database.reachable)
assert.is_number(json.server.connections_accepted)
assert.is_number(json.server.connections_active)
assert.is_number(json.server.connections_handled)
assert.is_number(json.server.connections_reading)
assert.is_number(json.server.connections_writing)
assert.is_number(json.server.connections_waiting)
assert.is_number(json.server.total_requests)
assert.is_string(json.configuration_hash)
assert.equal(32, #json.configuration_hash)

end)

it("database.reachable is `true` when DB connection is healthy", function()
Expand Down
42 changes: 41 additions & 1 deletion spec/02-integration/08-status_api/01-core_routes_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("Status API - with strategy #" .. strategy, function()
end)

describe("core", function()
it("/status returns status info", function()
it("/status returns status info without configuration_hash", function()
local res = assert(client:send {
method = "GET",
path = "/status"
Expand All @@ -40,7 +40,47 @@ describe("Status API - with strategy #" .. strategy, function()
assert.is_number(json.server.connections_writing)
assert.is_number(json.server.connections_waiting)
assert.is_number(json.server.total_requests)
assert.is_nil(json.server.configuration_hash) -- no hash in DB mode, or in DBLESS mode until configuration has been applied
end)

it("/status starts providing a config_hash once an initial configuration has been pushed in dbless mode #off", function()
-- push an initial configuration so that a configuration_hash will be present
local postres = assert(client:send {
method = "POST",
path = "/config",
body = {
config = [[
_format_version: "1.1"
services:
- host = "konghq.com"
]],
},
headers = {
["Content-Type"] = "application/json"
}
})
assert.res_status(201, postres)

local res = assert(client:send {
method = "GET",
path = "/status"
})
local body = assert.res_status(200, res)
local json = cjson.decode(body)
assert.is_table(json.database)
assert.is_table(json.server)
assert.is_boolean(json.database.reachable)
assert.is_number(json.server.connections_accepted)
assert.is_number(json.server.connections_active)
assert.is_number(json.server.connections_handled)
assert.is_number(json.server.connections_reading)
assert.is_number(json.server.connections_writing)
assert.is_number(json.server.connections_waiting)
assert.is_number(json.server.total_requests)
assert.is_string(json.server.configuration_hash)
assert.equal(32, #json.server.configuration_hash)
end)

end)

describe("plugins", function()
Expand Down

0 comments on commit 4f8c99d

Please sign in to comment.