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

fix(*) cassandra contact points initialization #4378

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions kong/db/strategies/cassandra/connector.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,77 @@ function CassandraConnector.new(kong_config)
do
-- Resolve contact points before instantiating cluster, since the
-- driver does not support hostnames in the contact points list.

-- TODO: this is an ugly hack to force lua sockets on a third party library
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be worth being more explicit here:

  • we force sync option for resty.dns.client to not spawn a timer
  • we force LuaSocket for resty.dns.resolver to not spawn a cosocket in init_by_lua

Can add at merge time, in fact let me take care of it, no worries 👍


local tcp_old = ngx.socket.tcp
local udp_old = ngx.socket.udp

local dns_no_sync_old = kong_config.dns_no_sync

package.loaded["socket"] = nil
package.loaded["kong.tools.dns"] = nil
package.loaded["resty.dns.client"] = nil
package.loaded["resty.dns.resolver"] = nil

ngx.socket.tcp = function(...)
local tcp = require("socket").tcp(...)
return setmetatable({}, {
__newindex = function(_, k, v)
tcp[k] = v
end,
__index = function(_, k)
if type(tcp[k]) == "function" then
return function(_, ...)
if k == "send" then
local value = select(1, ...)
if type(value) == "table" then
return tcp.send(tcp, table.concat(value))
end

return tcp.send(tcp, ...)
end

return tcp[k](tcp, ...)
end
end

return tcp[k]
end
})
end

ngx.socket.udp = function(...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for posterity:

ideally we should add support for ngx.socket.udp to lua-resty-socket and avoid duplicating the fallback logic there and here (lua-resty-socket has its own test suite and benefits other projects).

Copy link
Member Author

@bungle bungle Mar 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, looks like it already has all things covered. Lets add dependency to it with 1.1+.

local udp = require("socket").udp(...)
return setmetatable({}, {
__newindex = function(_, k, v)
udp[k] = v
end,
__index = function(_, k)
if type(udp[k]) == "function" then
return function(_, ...)
if k == "send" then
local value = select(1, ...)
if type(value) == "table" then
return udp.send(udp, table.concat(value))
end

return udp.send(udp, ...)
end

return udp[k](udp, ...)
end
end

return udp[k]
end
})
end

local dns_tools = require "kong.tools.dns"

kong_config.dns_no_sync = true

local dns = dns_tools(kong_config)

for i, cp in ipairs(kong_config.cassandra_contact_points) do
Expand All @@ -28,6 +98,16 @@ function CassandraConnector.new(kong_config)
resolved_contact_points[i] = ip
end
end

kong_config.dns_no_sync = dns_no_sync_old

package.loaded["resty.dns.resolver"] = nil
package.loaded["resty.dns.client"] = nil
package.loaded["kong.tools.dns"] = nil
package.loaded["socket"] = nil

ngx.socket.udp = udp_old
ngx.socket.tcp = tcp_old
end

if #resolved_contact_points == 0 then
Expand Down
31 changes: 31 additions & 0 deletions spec/02-integration/02-cmd/02-start_stop_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ describe("kong start/stop #" .. strategy, function()
assert(helpers.kong_exec("start --conf " .. helpers.test_conf_path))
assert.truthy(helpers.path.exists(helpers.test_conf.kong_env))
end)

if strategy == "cassandra" then
it("start resolves cassandra contact points", function()
assert(helpers.kong_exec("start", {
database = strategy,
cassandra_contact_points = "localhost",
cassandra_keyspace = helpers.test_conf.cassandra_keyspace,
}))
assert(helpers.kong_exec("stop"))
end)
end

it("creates prefix directory if it doesn't exist", function()
finally(function()
helpers.kill_all("foobar")
Expand Down Expand Up @@ -342,6 +354,25 @@ describe("kong start/stop #" .. strategy, function()
end
end)

if strategy == "cassandra" then
it("errors when cassandra contact points cannot be resolved", function()
local ok, stderr = helpers.kong_exec("start --prefix " .. helpers.test_conf.prefix, {
database = strategy,
cassandra_contact_points = "invalid.inexistent.host",
cassandra_keyspace = helpers.test_conf.cassandra_keyspace,
})

assert.False(ok)
assert.matches("could not resolve any of the provided Cassandra contact points " ..
"(cassandra_contact_points = 'invalid.inexistent.host')", stderr, nil, true)

finally(function()
helpers.kill_all()
pcall(helpers.dir.rmtree)
end)
end)
end

if strategy == "off" then
it("does not start with an invalid declarative config file", function()
local yaml_file = helpers.make_yaml_file [[
Expand Down