Skip to content

Commit eb14121

Browse files
authored
Merge pull request #271 from 3scale/dns-vol-2
DNS volume 2
2 parents b933f97 + 1e47e2d commit eb14121

18 files changed

+226
-93
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Use stale DNS cache when there is a query in progress for that record [PR #260](https://github.com/3scale/apicast/pull/260)
1313
- Bump s2i-openresty to 1.11.2.2-2 [PR #260](https://github.com/3scale/apicast/pull/260)
1414
- Echo API on port 8081 listens accepts any Host [PR #268](https://github.com/3scale/apicast/pull/268)
15+
- Always use DNS search scopes [PR #271](https://github.com/3scale/apicast/pull/271)
1516

1617
### Added
1718

apicast/src/configuration_loader/remote_v1.lua

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local tonumber = tonumber
55

66
local resty_url = require 'resty.url'
77
local http = require "resty.resolver.http"
8+
local socket_resolver = require('resty.resolver.socket')
89
local configuration_parser = require 'configuration_parser'
910
local user_agent = require 'user_agent'
1011
local env = require 'resty.env'
@@ -46,15 +47,15 @@ function _M.wait(endpoint, timeout)
4647
end
4748

4849
while now < fin do
49-
local sock = ngx.socket.tcp()
50+
local sock = socket_resolver.new(ngx.socket.tcp())
5051
local ok
5152

5253
ok, err = sock:connect(host, port)
5354

5455
if ok then
5556
ngx.log(ngx.DEBUG, 'connected to ' .. host .. ':' .. tostring(port))
5657
sock:close()
57-
return true
58+
break
5859
else
5960
ngx.log(ngx.DEBUG, 'failed to connect to ' .. host .. ':' .. tostring(port) .. ': ' .. err)
6061
end
@@ -64,7 +65,7 @@ function _M.wait(endpoint, timeout)
6465
now = ngx.now()
6566
end
6667

67-
return nil, err
68+
return not err, err
6869
end
6970

7071
function _M.download(endpoint, _)

apicast/src/proxy.lua

+2-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ local setmetatable = setmetatable
1919
local exit = ngx.exit
2020
local encode_args = ngx.encode_args
2121
local resty_resolver = require 'resty.resolver'
22-
local dns_resolver = require 'resty.resolver.dns'
2322
local empty = {}
2423

2524
local response_codes = env.enabled('APICAST_RESPONSE_CODES')
@@ -287,9 +286,7 @@ end
287286
function _M.set_upstream(service)
288287
local upstream = _M.get_upstream(service)
289288

290-
ngx.ctx.dns = dns_resolver:new{ nameservers = resty_resolver.nameservers() }
291-
ngx.ctx.resolver = resty_resolver.new(ngx.ctx.dns)
292-
ngx.ctx.upstream = ngx.ctx.resolver:get_servers(upstream.server, { port = upstream.port })
289+
ngx.ctx.upstream = resty_resolver:instance():get_servers(upstream.server, { port = upstream.port })
293290

294291
ngx.var.proxy_pass = upstream.uri
295292
ngx.req.set_header('Host', upstream.host or ngx.var.host)
@@ -307,10 +304,7 @@ function _M:set_backend_upstream(service)
307304
local scheme, _, _, server, port, path =
308305
url[1], url[2], url[3], url[4], url[5] or resty_url.default_port(url[1]), url[6] or ''
309306

310-
ngx.ctx.dns = ngx.ctx.dns or dns_resolver:new{ nameservers = resty_resolver.nameservers() }
311-
ngx.ctx.resolver = ngx.ctx.resolver or resty_resolver.new(ngx.ctx.dns)
312-
313-
local backend_upstream = ngx.ctx.resolver:get_servers(server, { port = port or nil })
307+
local backend_upstream = resty_resolver:instance():get_servers(server, { port = port or nil })
314308
ngx.log(ngx.DEBUG, '[resolver] resolved backend upstream: ', #backend_upstream)
315309
ngx.ctx.backend_upstream = backend_upstream
316310

apicast/src/resty/resolver.lua

+47-33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ local io_type = io.type
1212
local re_match = ngx.re.match
1313
local semaphore = require "ngx.semaphore"
1414
local resolver_cache = require 'resty.resolver.cache'
15+
local dns_client = require 'resty.resolver.dns_client'
1516
local re = require('ngx.re')
1617

1718
local init = semaphore.new(1)
@@ -30,16 +31,12 @@ local default_resolver_port = 53
3031
local _M = {
3132
_VERSION = '0.1',
3233
_nameservers = {},
33-
search = {}
34+
search = { '' }
3435
}
3536

3637
local mt = { __index = _M }
3738

38-
function _M.parse_nameservers(path)
39-
local search = {}
40-
local nameservers = { search = search }
41-
local resolver = getenv('RESOLVER')
42-
39+
local function read_resolv_conf(path)
4340
path = path or '/etc/resolv.conf'
4441

4542
local handle, err
@@ -56,13 +53,25 @@ function _M.parse_nameservers(path)
5653
handle:seek("set")
5754
output = handle:read("*a")
5855
handle:close()
59-
else
60-
ngx.log(ngx.ERR, 'resolver could not get nameservers: ', err)
61-
return nil, err
6256
end
63-
ngx.log(ngx.DEBUG, '/etc/resolv.conf:\n', output)
6457

65-
local domains = match(output, 'search%s+([^\n]+)')
58+
return output or "", err
59+
end
60+
61+
function _M.parse_nameservers(path)
62+
local resolv_conf, err = read_resolv_conf(path)
63+
64+
if err then
65+
ngx.log(ngx.WARN, 'resolver could not get nameservers: ', err)
66+
end
67+
68+
ngx.log(ngx.DEBUG, '/etc/resolv.conf:\n', resolv_conf)
69+
70+
local search = { '' }
71+
local nameservers = { search = search }
72+
local resolver = getenv('RESOLVER')
73+
local domains = match(resolv_conf, 'search%s+([^\n]+)')
74+
6675
ngx.log(ngx.DEBUG, 'search ', domains)
6776
for domain in gmatch(domains or '', '([^%s]+)') do
6877
ngx.log(ngx.DEBUG, 'search domain: ', domain)
@@ -75,7 +84,7 @@ function _M.parse_nameservers(path)
7584
return nameservers
7685
end
7786

78-
for nameserver in gmatch(output, 'nameserver%s+([^%s]+)') do
87+
for nameserver in gmatch(resolv_conf, 'nameserver%s+([^%s]+)') do
7988
-- TODO: implement port matching based on https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=549190
8089
if nameserver ~= resolver then
8190
insert(nameservers, { nameserver, default_resolver_port } )
@@ -133,6 +142,18 @@ function _M.new(dns, opts)
133142
}, mt)
134143
end
135144

145+
function _M:instance()
146+
local ctx = ngx.ctx
147+
local resolver = ctx.resolver
148+
149+
if not resolver then
150+
local dns = dns_client:instance(self.nameservers())
151+
resolver = self.new(dns)
152+
ctx.resolver = resolver
153+
end
154+
155+
return resolver
156+
end
136157

137158
local function new_server(answer, port)
138159
if not answer then return nil, 'missing answer' end
@@ -164,14 +185,6 @@ local function is_ip(address)
164185
end
165186
end
166187

167-
local function has_tld(qname)
168-
return match(qname, '%.')
169-
end
170-
171-
local function have_addresses(answers)
172-
return answers and next(answers.addresses or {}) and #answers > 0 and not answers.errcode
173-
end
174-
175188
local function convert_answers(answers, port)
176189
local servers = {}
177190

@@ -184,6 +197,8 @@ local function convert_answers(answers, port)
184197
return servers
185198
end
186199

200+
local empty = {}
201+
187202
local function lookup(dns, qname, search, options)
188203
ngx.log(ngx.DEBUG, 'resolver query: ', qname)
189204

@@ -193,22 +208,18 @@ local function lookup(dns, qname, search, options)
193208
ngx.log(ngx.DEBUG, 'host is ip address: ', qname)
194209
answers = { new_answer(qname) }
195210
else
196-
answers, err = dns:query(qname, options)
197-
198-
if not has_tld(qname) and not have_addresses(answers) then
199-
for i=1, #search do
211+
for i=1, #search do
212+
local query = qname .. '.' .. search[i]
213+
ngx.log(ngx.DEBUG, 'resolver query: ', qname, ' search: ', search[i], ' query: ', query)
214+
answers, err = dns:query(query, options)
200215

201-
local query = qname .. '.' .. search[i]
202-
ngx.log(ngx.DEBUG, 'resolver query: ', qname, ' search: ', search[i], ' query: ', query)
203-
answers, err = dns:query(query, options)
204-
205-
if answers and not answers.errcode and #answers > 0 then
206-
break
207-
end
216+
if answers and not answers.errcode and #answers > 0 then
217+
break
208218
end
209219
end
210220
end
211221

222+
ngx.log(ngx.DEBUG, 'resolver query: ', qname, ' finished with ', #(answers or empty), ' answers')
212223
return answers, err
213224
end
214225

@@ -225,8 +236,7 @@ function _M.get_servers(self, qname, opts)
225236
end
226237

227238
local cache = self.cache
228-
local search = self.search or {}
229-
239+
local search = self.search or _M.search
230240

231241
-- TODO: pass proper options to dns resolver (like SRV query type)
232242

@@ -245,13 +255,17 @@ function _M.get_servers(self, qname, opts)
245255
end
246256

247257
if err then
258+
ngx.log(ngx.DEBUG, 'query for ', qname, ' finished with error: ', err)
248259
return {}, err
249260
end
250261

251262
if not answers then
263+
ngx.log(ngx.DEBUG, 'query for ', qname, ' finished with no answers')
252264
return {}, 'no answers'
253265
end
254266

267+
ngx.log(ngx.DEBUG, 'query for ', qname, ' finished with ' , #answers, ' answers')
268+
255269
local servers = convert_answers(answers, opts.port)
256270

257271
servers.query = qname

apicast/src/resty/resolver/dns.lua renamed to apicast/src/resty/resolver/dns_client.lua

+52-9
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,32 @@ function _M.new(_, options)
2424
}, mt)
2525
end
2626

27+
function _M:instance(nameservers)
28+
local ctx = ngx.ctx
29+
local resolver = ctx.dns
30+
31+
if not resolver then
32+
resolver = self:new({ nameservers = nameservers })
33+
ctx.dns = resolver
34+
end
35+
36+
return resolver
37+
end
38+
2739
function _M:init_resolvers()
2840
local resolvers = self.resolvers
2941
local nameservers = self.nameservers
3042

43+
ngx.log(ngx.DEBUG, 'initializing ', #nameservers, ' nameservers')
3144
for i=1,#nameservers do
32-
insert(resolvers, { nameservers[i], resty_resolver:new({ nameservers = { nameservers[i] }}) })
45+
insert(resolvers, {
46+
nameserver = nameservers[i],
47+
resolver = resty_resolver:new({
48+
nameservers = { nameservers[i] },
49+
timeout = 2900
50+
})
51+
})
52+
ngx.log(ngx.DEBUG, 'nameserver ', nameservers[i][1],':',nameservers[i][2] or 53, ' initialized')
3353
end
3454

3555
self.initialized = true
@@ -42,18 +62,16 @@ local function query(resolver, qname, opts, nameserver)
4262
return resolver:query(qname, opts)
4363
end
4464

45-
function _M.query(self, qname, opts)
46-
local resolvers = self.resolvers
47-
48-
if not self.initialized then
49-
resolvers = self:init_resolvers()
50-
end
51-
65+
local function parallel_query(resolvers, qname, opts)
5266
local threads = {}
5367
local n = #resolvers
5468

69+
if n < 1 then
70+
return nil, 'no resolvers'
71+
end
72+
5573
for i=1, n do
56-
insert(threads, th_spawn(query, resolvers[i][2], qname, opts, resolvers[i][1]))
74+
insert(threads, th_spawn(query, resolvers[i].resolver, qname, opts, resolvers[i].nameserver))
5775
end
5876

5977
local answers, err
@@ -75,4 +93,29 @@ function _M.query(self, qname, opts)
7593
return answers, err
7694
end
7795

96+
local function serial_query(resolvers, qname, opts)
97+
local answers, err
98+
99+
for i=1, #resolvers do
100+
answers, err = query(resolvers[i].resolver, qname, opts, resolvers[i].nameserver)
101+
102+
if answers and not answers.errcode and not err then
103+
break
104+
end
105+
end
106+
107+
return answers
108+
end
109+
110+
function _M.query(self, qname, opts)
111+
local resolvers = self.resolvers
112+
113+
if not self.initialized then
114+
resolvers = self:init_resolvers()
115+
end
116+
117+
-- this is here so you can try the other one when suspicous something is wrong
118+
return (parallel_query or serial_query)(resolvers, qname, opts)
119+
end
120+
78121
return _M

apicast/src/resty/resolver/http.lua

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
local resty_http = require 'resty.http'
2-
local dns_resolver = require 'resty.resolver.dns'
32
local resty_resolver = require 'resty.resolver'
43
local round_robin = require 'resty.balancer.round_robin'
54

@@ -12,9 +11,8 @@ local mt = { __index = _M }
1211

1312
function _M.new()
1413
local http = resty_http:new()
15-
local dns = dns_resolver:new{ nameservers = resty_resolver.nameservers() }
1614

17-
http.resolver = resty_resolver.new(dns)
15+
http.resolver = resty_resolver:instance()
1816
http.balancer = round_robin.new()
1917

2018
return setmetatable(http, mt)

0 commit comments

Comments
 (0)