lua

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

Goals

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

Solution

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/

  1. Declare in the global block the Lua scripts:

    global
        lua-load /etc/haproxy/checktcp.lua
  2. 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.

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

  4. 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)
  5. And that’s all: just restart HAProxy now.