Lua has been added in HAProxy a long time ago but I never tested it.
A recent project gave me the opportunity to test it… and it works great
For this project I needed to test the end-to-end availability of a TCP server from an external load-balancer
(Cloudflare DNS Load Balancer) that don’t know how to talk to a TCP
It have options to test HTML return codes or HTML page body contents but it cannot send a TCP message and check it.
What I need to implement
- I need an end-to-end test: so I must talk with my TCP service to check if it’s alive
- the external Load Balancer needs an HTML status page: so I must send him a HTML code
As it was not an option to add a HTTP listener to the TCP service, I decided to see how HAProxy and Lua could help me.
It was really simple and straight-forward.
I used the really good (as usual) blog post from the HAProxy blog team: https://www.haproxy.com/fr/blog/5-ways-to-extend-haproxy-with-lua/
Declare in the global block the Lua scripts:
global lua-load /etc/haproxy/checktcp.lua
Identify the kind of script you need (there are 5): check the blog post to find the one you need.
For my use-case, I need the service kind.
This one is really interesting for me as it allows to generates HTML page.
Write the rules in the frontends/backends: it depends of what kind of script you wrote.
For my use-case, the script will handle requests in the backend:
frontend fe_main bind *:80 default_backend checktcp backed checktcp mode http http-request use-service lua.checktcp
Of course, you cadd all kind of ACL and rules.
Write the script.
Probably the most difficult part but you have access to all Lua libraries found on your system and the inner API from HAProxy (http://www.arpalert.org/haproxy-api.html).
Mine is really simple: - it connects to the TCP server and send a message: ‘check’ - it removes the first line of the response (it’s a header with some information like IPs) - it check the next line to see if it sees the word ‘check’ - if so, it creates a HTML page with an ‘OK’ text and return the code 200 - otherwise, it creates a HTML page with a ‘KO’ text and return the code 503
local function checktcp(applet) local addr = '127.0.0.1' local port = 8080 local code = 503 local response = "KO\r\n" -- Use core.tcp to get an instance of the Socket class local socket = core.tcp() socket:settimeout(1) -- Connect to the service and send the request if socket:connect(addr, port) then if socket:send("check\n") then -- Skip response headers socket:receive('*l') -- Get the content local content = socket:receive('*l') if content and content == "check" then code = 200 response = "OK\r\n" end end socket:close() end applet:set_status(code) applet:add_header("content-length", string.len(response)) applet:add_header("content-type", "text/html") applet:start_response() applet:send(response) end core.register_service("checktcp", "http", checktcp)
And that’s all: just restart HAProxy now.