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

dnsmasq integration #194

Merged
merged 2 commits into from
May 9, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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" },
Copy link
Member Author

Choose a reason for hiding this comment

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

@thibaultcha did you mean like this? The name is unfortunate but I am testing DNS resolution so dns1.com and dns2.com make sense here.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah it's nice it's enough to know it's for the DNS. We'll move them out of the faker and to their own respective tests later.


-- 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