From 1159fcc475b1839d22cb68332284a97a8685477f Mon Sep 17 00:00:00 2001 From: Aapo Talvensaari Date: Fri, 8 Mar 2019 18:19:07 -0800 Subject: [PATCH] fix(*) cassandra contact points initialization C* doesn't initialize contact points correctly when the contact points need to be resolved with DNS. DNS on the other hand uses Nginx cosockets that cannot be used with init phase. Nginx cosockets are not fully compatible with lua sockets. This PR is a quick fix for the issue. --- kong/db/strategies/cassandra/connector.lua | 80 +++++++++++++++++++ .../02-cmd/02-start_stop_spec.lua | 31 +++++++ 2 files changed, 111 insertions(+) diff --git a/kong/db/strategies/cassandra/connector.lua b/kong/db/strategies/cassandra/connector.lua index c27278655ff..486ef6e2f96 100644 --- a/kong/db/strategies/cassandra/connector.lua +++ b/kong/db/strategies/cassandra/connector.lua @@ -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 + + 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(...) + 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 @@ -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 diff --git a/spec/02-integration/02-cmd/02-start_stop_spec.lua b/spec/02-integration/02-cmd/02-start_stop_spec.lua index a9a42a19bf3..ddc45c2bb80 100644 --- a/spec/02-integration/02-cmd/02-start_stop_spec.lua +++ b/spec/02-integration/02-cmd/02-start_stop_spec.lua @@ -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") @@ -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 [[