Skip to content

Commit

Permalink
dnsmasq integration for better DNS resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
subnetmarco committed May 9, 2015
1 parent 8acfe1d commit 845bf59
Show file tree
Hide file tree
Showing 17 changed files with 182 additions and 26 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ before_install:
- bash .travis/setup_openresty.sh
- export PATH=$PATH:/usr/local/openresty/nginx/sbin
- bash .travis/setup_cassandra.sh
- bash .travis/setup_dnsmasq.sh

install:
- sudo make install
- sudo make dev

script: "busted --coverage spec/"

after_success: "luacov-coveralls -i kong"
after_success: "luacov-coveralls -i kong"
4 changes: 4 additions & 0 deletions .travis/setup_dnsmasq.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

sudo apt-get update && sudo apt-get install dnsmasq sudo
echo -e "user=root" | sudo tee /etc/dnsmasq.conf
3 changes: 2 additions & 1 deletion kong.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ nginx_working_dir: /usr/local/kong/

proxy_port: 8000
admin_api_port: 8001
dnsmasq_port: 8053

# Specify the DAO to use
database: cassandra
Expand Down Expand Up @@ -49,7 +50,7 @@ nginx: |
}
http {
resolver 8.8.8.8;
resolver {{dns_resolver}};
charset UTF-8;
access_log logs/access.log;
Expand Down
2 changes: 1 addition & 1 deletion kong/cli/quit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if not running then
end

-- Send 'quit' signal (graceful shutdown)
if signal.send_signal(args.config, "quit") then
if signal.send_signal(args.config, signal.QUIT) then
cutils.logger:success("Stopped")
else
cutils.logger:error_exit("Could not gracefully stop Kong")
Expand Down
2 changes: 1 addition & 1 deletion kong/cli/reload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ end

signal.prepare_kong(args.config)

if signal.send_signal(args.config, "reload") then
if signal.send_signal(args.config, signal.RELOAD) then
cutils.logger:success("Reloaded")
else
cutils.logger:error_exit("Could not reload Kong")
Expand Down
2 changes: 1 addition & 1 deletion kong/cli/restart.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Options:
]], constants.CLI.GLOBAL_KONG_CONF))

if signal.is_running(args.config) then
if not signal.send_signal(args.config, "stop") then
if not signal.send_signal(args.config, signal.STOP) then
cutils.logger:error_exit("Could not stop Kong")
end
end
Expand Down
2 changes: 1 addition & 1 deletion kong/cli/stop.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if not running then
end

-- Send 'stop' signal (fast shutdown)
if signal.send_signal(args.config, "stop") then
if signal.send_signal(args.config, signal.STOP) then
cutils.logger:success("Stopped")
else
cutils.logger:error_exit("Could not stop Kong")
Expand Down
71 changes: 67 additions & 4 deletions kong/cli/utils/signal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local IO = require "kong.tools.io"
local cutils = require "kong.cli.utils"
local constants = require "kong.constants"
local syslog = require "kong.tools.syslog"
local stringy = require "stringy"

-- Cache config path, parsed config and DAO factory
local kong_config_path
Expand Down Expand Up @@ -87,7 +88,8 @@ local function prepare_nginx_working_dir(args_config)
local nginx_config = kong_config.nginx
local nginx_inject = {
proxy_port = kong_config.proxy_port,
admin_api_port = kong_config.admin_api_port
admin_api_port = kong_config.admin_api_port,
dns_resolver = "127.0.0.1:"..kong_config.dnsmasq_port
}

-- Auto-tune
Expand Down Expand Up @@ -153,12 +155,55 @@ local function prepare_database(args_config)
end
end

local function stop_dnsmasq(kong_config)
local file_pid = kong_config.nginx_working_dir.."/"..constants.CLI.DNSMASQ_PID
if IO.file_exists(file_pid) then
local res, code = IO.os_execute("cat "..file_pid)
if code == 0 then
local _, kill_code = IO.kill_process_by_pid(res)
if kill_code and kill_code == 0 then
cutils.logger:info("dnsmasq stopped")
end
else
cutils.logger:error_exit(res)
end
end
end

local function start_dnsmasq(kong_config)
local cmd = IO.cmd_exists("dnsmasq") and "dnsmasq" or
(IO.cmd_exists("/usr/local/sbin/dnsmasq") and "/usr/local/sbin/dnsmasq" or nil) -- On OS X dnsmasq is at /usr/local/sbin/
if not cmd then
cutils.logger:error_exit("Can't find dnsmasq")
end

-- Start the dnsmasq
local file_pid = kong_config.nginx_working_dir..(stringy.endswith(kong_config.nginx_working_dir, "/") and "" or "/")..constants.CLI.DNSMASQ_PID
local res, code = IO.os_execute(cmd.." -p "..kong_config.dnsmasq_port.." --pid-file="..file_pid)
if code ~= 0 then
cutils.logger:error_exit(res)
else
cutils.logger:info("dnsmasq started")
end
end

--
-- PUBLIC
--

local _M = {}

-- Constants
local START = "start"
local RESTART = "restart"
local RELOAD = "reload"
local STOP = "stop"
local QUIT = "quit"

_M.RELOAD = RELOAD
_M.STOP = STOP
_M.QUIT = QUIT

function _M.prepare_kong(args_config)
local kong_config = get_kong_config(args_config)
local dao_config = kong_config.databases_available[kong_config.database].properties
Expand All @@ -169,10 +214,12 @@ function _M.prepare_kong(args_config)
-- Print important informations
cutils.logger:info(string.format([[Proxy port.........%s
Admin API port.....%s
dnsmasq port.......%s
Database...........%s %s
]],
kong_config.proxy_port,
kong_config.admin_api_port,
kong_config.dnsmasq_port,
kong_config.database,
tostring(dao_config)))

Expand Down Expand Up @@ -205,19 +252,35 @@ function _M.send_signal(args_config, signal)
constants.CLI.NGINX_PID,
signal ~= nil and "-s "..signal or "")

if not signal then signal = "start" end
if signal == "start" or signal == "restart" or signal == "reload" then
if not signal then signal = START end

if signal == START then
stop_dnsmasq(kong_config)
start_dnsmasq(kong_config)
end

if signal == STOP then
stop_dnsmasq(kong_config)
end

-- Check ulimit value
if signal == START or signal == RESTART or signal == RELOAD then
local res, code = IO.os_execute("ulimit -n")
if code == 0 and tonumber(res) < 4096 then
cutils.logger:warn("ulimit is currently set to \""..res.."\". For better performance set it to at least \"4096\" using \"ulimit -n\"")
end
end

-- Check settings for anonymous reports
if kong_config.send_anonymous_reports then
syslog.log({signal=signal})
end

return os.execute(cmd) == 0
local success = os.execute(cmd) == 0
if signal == START and not success then
stop_dnsmasq(kong_config)
end
return success
end

-- Test if Kong is already running by detecting a pid file.
Expand Down
3 changes: 2 additions & 1 deletion kong/constants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ return {
CLI = {
GLOBAL_KONG_CONF = "/etc/kong/kong.yml",
NGINX_CONFIG = "nginx.conf",
NGINX_PID = "kong.pid"
NGINX_PID = "kong.pid",
DNSMASQ_PID = "dnsmasq.pid",
},
DATABASE_NULL_ID = "00000000-0000-0000-0000-000000000000",
DATABASE_ERROR_TYPES = {
Expand Down
3 changes: 3 additions & 0 deletions kong/tools/faker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ Faker.FIXTURES = {
{ name = "API TESTS 6", public_dns = "cors1.com", target_url = "http://mockbin.com" },
{ name = "API TESTS 7", public_dns = "cors2.com", target_url = "http://mockbin.com" },

{ name = "API TESTS 8 (dns)", public_dns = "dns1.com", target_url = "http://127.0.0.1:7771" },
{ name = "API TESTS 9 (dns)", public_dns = "dns2.com", target_url = "http://localhost:7771" },

-- DEVELOPMENT APIs. Please do not use those in tests
{ name = "API DEV 1", public_dns = "dev.com", target_url = "http://mockbin.com" },
},
Expand Down
42 changes: 32 additions & 10 deletions kong/tools/io.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
local constants = require "kong.constants"
local path = require("path").new("/")
local yaml = require "yaml"
local stringy = require "stringy"

local _M = {}

_M.path = path

function _M.file_exists(name)
local f, err = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false, err
end
end

function _M.os_execute(command)
local n = os.tmpname() -- get a temporary file name to store output
local exit_code = os.execute("/bin/bash -c '"..command.." > "..n.." 2>&1'")
Expand All @@ -15,6 +26,20 @@ function _M.os_execute(command)
return string.gsub(result, "[%\r%\n]", ""), exit_code / 256
end

function _M.cmd_exists(cmd)
local _, code = _M.os_execute("hash "..cmd)
return code == 0
end

-- Kills a process by PID and waits until it's terminated
--
-- @param {string} the pid to kill
function _M.kill_process_by_pid(pid, signal)
local res, code = _M.os_execute("kill "..(signal and "-"..tostring(signal).." " or "")..pid)
_M.os_execute("wait "..pid)
return res, code
end

function _M.read_file(path)
local contents = nil
local file = io.open(path, "rb")
Expand All @@ -36,16 +61,6 @@ function _M.write_to_file(path, value)
return true
end

function _M.file_exists(name)
local f = io.open(name, "r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end

function _M.retrieve_files(dir, options)
local fs = require "luarocks.fs"
local pattern = options.file_pattern
Expand Down Expand Up @@ -91,6 +106,13 @@ function _M.load_configuration_and_dao(configuration_path)
-- Alias the DAO configuration we are using for this instance for easy access
configuration.dao_config = dao_config

-- Load absolute path for the nginx working directory
if not stringy.startswith(configuration.nginx_working_dir, "/") then
-- It's a relative path, convert it to absolute
local fs = require "luarocks.fs"
configuration.nginx_working_dir = fs.current_dir().."/"..configuration.nginx_working_dir
end

-- Instanciate the DAO Factory along with the configuration
local DaoFactory = require("kong.dao."..configuration.database..".factory")
local dao_factory = DaoFactory(dao_config.properties)
Expand Down
59 changes: 59 additions & 0 deletions spec/integration/proxy/dns_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
local spec_helper = require "spec.spec_helpers"
local http_client = require "kong.tools.http_client"
local Threads = require "llthreads2.ex"

local STUB_GET_URL = spec_helper.STUB_GET_URL

local function start_tcp_server()
local thread = Threads.new({
function()
local socket = require "socket"
local server = assert(socket.bind("*", 7771))
local client = server:accept()
local line, err = client:receive()
local message = "{\"ok\": true}"
if not err then client:send("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: "..string.len(message).."\r\n\r\n"..message) end
client:close()
return line
end;
})

thread:start()
return thread;
end

describe("DNS", function()

setup(function()
spec_helper.prepare_db()
spec_helper.start_kong()
end)

teardown(function()
spec_helper.stop_kong()
spec_helper.reset_db()
end)

describe("DNS", function()

it("should work when calling local IP", function()
local thread = start_tcp_server() -- Starting the mock TCP server

local response, status = http_client.get(spec_helper.STUB_GET_URL, nil, { host = "dns1.com" })
assert.are.equal(200, status)

thread:join() -- Wait til it exists
end)

it("should work when calling local hostname", function()
local thread = start_tcp_server() -- Starting the mock TCP server

local response, status = http_client.get(spec_helper.STUB_GET_URL, nil, { host = "dns2.com" })
assert.are.equal(200, status)

thread:join() -- Wait til it exists
end)

end)

end)
1 change: 0 additions & 1 deletion spec/integration/proxy/realip_spec.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
local spec_helper = require "spec.spec_helpers"
local http_client = require "kong.tools.http_client"
local Threads = require "llthreads2.ex"
local cjson = require "cjson"
local yaml = require "yaml"
local IO = require "kong.tools.io"
Expand Down
4 changes: 2 additions & 2 deletions spec/spec_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function _M.start_kong(conf_file, skip_wait)
end

if not skip_wait then
os.execute("while ! [ -f "..env.configuration.pid_file.." ]; do sleep 1; done")
os.execute("while ! [ -f "..env.configuration.pid_file.." ]; do sleep 0.5; done")
end

return result, exit_code
Expand All @@ -72,7 +72,7 @@ function _M.stop_kong(conf_file)
error("spec_helper cannot stop kong: "..result)
end

os.execute("while [ -f "..env.configuration.pid_file.." ]; do sleep 1; done")
os.execute("while [ -f "..env.configuration.pid_file.." ]; do sleep 0.5; done")

return result, exit_code
end
Expand Down
3 changes: 2 additions & 1 deletion spec/unit/statics_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ nginx_working_dir: /usr/local/kong/
proxy_port: 8000
admin_api_port: 8001
dnsmasq_port: 8053
# Specify the DAO to use
database: cassandra
Expand Down Expand Up @@ -86,7 +87,7 @@ nginx: |
}
http {
resolver 8.8.8.8;
resolver {{dns_resolver}};
charset UTF-8;
access_log logs/access.log;
Expand Down
Loading

0 comments on commit 845bf59

Please sign in to comment.