add support for ExternalName service type in dynamic mode

This commit is contained in:
Elvin Efendi 2018-07-17 22:27:10 -04:00
parent bdb5ddc473
commit d4faf68416
13 changed files with 316 additions and 18 deletions

View file

@ -77,6 +77,44 @@ describe("Balancer", function()
assert.spy(s).was_called_with(implementation, backend)
end)
it("resolves external name to endpoints when service is of type External name", function()
backend = {
name = "exmaple-com", service = { spec = { ["type"] = "ExternalName" } },
endpoints = {
{ address = "example.com", port = "80", maxFails = 0, failTimeout = 0 }
}
}
local dns_helper = require("test/dns_helper")
dns_helper.mock_dns_query({
{
name = "example.com",
address = "192.168.1.1",
ttl = 3600,
},
{
name = "example.com",
address = "1.2.3.4",
ttl = 60,
}
})
expected_backend = {
name = "exmaple-com", service = { spec = { ["type"] = "ExternalName" } },
endpoints = {
{ address = "192.168.1.1", port = "80" },
{ address = "1.2.3.4", port = "80" },
}
}
local mock_instance = { sync = function(backend) end }
setmetatable(mock_instance, implementation)
implementation.new = function(self, backend) return mock_instance end
assert.has_no.errors(function() balancer.sync_backend(backend) end)
stub(mock_instance, "sync")
assert.has_no.errors(function() balancer.sync_backend(backend) end)
assert.stub(mock_instance.sync).was_called_with(mock_instance, expected_backend)
end)
it("replaces the existing balancer when load balancing config changes for backend", function()
assert.has_no.errors(function() balancer.sync_backend(backend) end)

View file

@ -0,0 +1,27 @@
local _M = {}
local configuration = require("configuration")
local resolver = require("resty.dns.resolver")
local old_resolver_new = resolver.new
local function reset(nameservers)
configuration.nameservers = nameservers or { "1.1.1.1" }
end
function _M.mock_new(func, nameservers)
reset(nameservers)
resolver.new = func
end
function _M.mock_dns_query(response, err)
reset()
resolver.new = function(self, options)
local r = old_resolver_new(self, options)
r.query = function(self, name, options, tries)
return response, err
end
return r
end
end
return _M

View file

@ -0,0 +1,32 @@
local ffi = require("ffi")
-- without this we get errors such as "attempt to redefine XXX"
local old_cdef = ffi.cdef
local exists = {}
ffi.cdef = function(def)
if exists[def] then
return
end
exists[def] = true
return old_cdef(def)
end
local old_udp = ngx.socket.udp
ngx.socket.udp = function(...)
local socket = old_udp(...)
socket.send = function(...)
error("ngx.socket.udp:send please mock this to use in tests")
end
return socket
end
local old_tcp = ngx.socket.tcp
ngx.socket.tcp = function(...)
local socket = old_tcp(...)
socket.send = function(...)
error("ngx.socket.tcp:send please mock this to use in tests")
end
return socket
end
require "busted.runner"({ standalone = false })

View file

@ -0,0 +1,74 @@
describe("resolve", function()
local dns = require("util.dns")
local dns_helper = require("test/dns_helper")
it("sets correct nameservers", function()
dns_helper.mock_new(function(self, options)
assert.are.same({ nameservers = { "1.2.3.4", "4.5.6.7" }, retrans = 5, timeout = 2000 }, options)
return nil, ""
end, { "1.2.3.4", "4.5.6.7" })
dns.resolve("example.com")
end)
it("returns host when an error happens", function()
local s_ngx_log = spy.on(ngx, "log")
dns_helper.mock_new(function(...) return nil, "an error" end)
assert.are.same({ "example.com" }, dns.resolve("example.com"))
assert.spy(s_ngx_log).was_called_with(ngx.ERR, "failed to instantiate the resolver: an error")
dns_helper.mock_dns_query(nil, "oops!")
assert.are.same({ "example.com" }, dns.resolve("example.com"))
assert.spy(s_ngx_log).was_called_with(ngx.ERR, "failed to query the DNS server: oops!")
dns_helper.mock_dns_query({ errcode = 1, errstr = "format error" })
assert.are.same({ "example.com" }, dns.resolve("example.com"))
assert.spy(s_ngx_log).was_called_with(ngx.ERR, "server returned error code: 1: format error")
dns_helper.mock_dns_query({})
assert.are.same({ "example.com" }, dns.resolve("example.com"))
assert.spy(s_ngx_log).was_called_with(ngx.ERR, "no A record resolved")
dns_helper.mock_dns_query({ { name = "example.com", cname = "sub.example.com", ttl = 60 } })
assert.are.same({ "example.com" }, dns.resolve("example.com"))
assert.spy(s_ngx_log).was_called_with(ngx.ERR, "no A record resolved")
end)
it("resolves all A records of given host, caches them with minimal ttl and returns from cache next time", function()
dns_helper.mock_dns_query({
{
name = "example.com",
address = "192.168.1.1",
ttl = 3600,
},
{
name = "example.com",
address = "1.2.3.4",
ttl = 60,
}
})
local lrucache = require("resty.lrucache")
local old_lrucache_new = lrucache.new
lrucache.new = function(...)
local cache = old_lrucache_new(...)
local old_set = cache.set
cache.set = function(self, key, value, ttl)
assert.equal("example.com", key)
assert.are.same({ "192.168.1.1", "1.2.3.4" }, value)
assert.equal(60, ttl)
return old_set(self, key, value, ttl)
end
return cache
end
assert.are.same({ "192.168.1.1", "1.2.3.4" }, dns.resolve("example.com"))
dns_helper.mock_new(function(...)
error("expected to short-circuit and return response from cache")
end)
assert.are.same({ "192.168.1.1", "1.2.3.4" }, dns.resolve("example.com"))
end)
end)