Skip to content

Instantly share code, notes, and snippets.

@haproxytechblog
Last active June 22, 2023 20:23
Show Gist options
  • Save haproxytechblog/687109453ec97c686f89dacea9252d86 to your computer and use it in GitHub Desktop.
Save haproxytechblog/687109453ec97c686f89dacea9252d86 to your computer and use it in GitHub Desktop.
Your Starter Guide to Using the HAProxy Lua Event Framework
-- Make an http post request to a webhook endpoint to notify about a backend
-- going down at a given time. For the sake of the example, contextual data
-- is formatted in JSON, webhook handlers often rely on a combination of
-- headers and plain POST or JSON formatted POST payloads to extract arguments
-- from the request.
local function backend_is_down(backend, when)
local httpclient = core.httpclient()
local api_base_url = os.getenv("DEMO_WEBHOOK_URL")
local request_body = string.format("{\
\"type\":\"%s\",\
\"name\":\"%s\",\
\"when\":\"%d\"\
}",
"backend_down",
backend,
when)
local response = httpclient:post{url = api_base_url, body=request_body}
if (response.status ~= 200) then
core.Alert("Error when making request to http endpoint")
end
end
-- this function will be called by event framework each time a server
-- from the chosen backend will be transitioning from UP to DOWN
local function server_down(event, data, mgmt, when)
local server = data.reference -- get a reference to the server
if server == nil then
-- the server has been removed, we cannot fetch
-- (should not happen in our testcase)
return
end
if server:get_proxy():get_srv_act() == 0 then
-- no more active servers within the backend, trigger an alert
backend_is_down(server:get_proxy():get_name(), when)
end
end
local arguments = table.pack(...) -- fetch global arguments from lua-load
core.register_init(function()
-- foreach backend name in arguments
for index,name in ipairs(arguments) do
-- register server_down function for DOWN event for every server
-- within current backend
for srv_name, srv in pairs(core.backends[name].servers) do
srv:event_sub({"SERVER_DOWN"}, server_down)
end
end
end)
-- watch for new server addition
core.event_sub({"SERVER_ADD"}, function(event, data)
local server = data.reference -- get a reference to the server
if server == nil then
return
end
-- as new server has been added dynamically, check if it belongs to
-- one of the tracked backends passed as optional lua-load arguments
for index,name in ipairs(arguments) do
if name == server:get_proxy():get_name() then
-- track the server for DOWN event
server:event_sub({"SERVER_DOWN"}, server_down)
break
end
end
end)
$ make TARGET=linux-glibc USE_LUA=1 -j$(nproc)
$ make TARGET=linux-glibc USE_LUA=1 LUA_LIB=/path/to/lua/lib LUA_INC=/path/to/lua/lib/include -j$(nproc)
$ ./haproxy -vv | grep Lua
Built with Lua version : Lua 5.4.6
-- Make an http post request to a webhook endpoint to notify about a backend
-- going down at a given time. For the sake of the example, contextual data
-- is formatted in JSON, webhook handlers often rely on a combination of
-- headers and plain POST or JSON formatted POST payloads to extract arguments
-- from the request.
local function backend_is_down(backend, when)
local httpclient = core.httpclient()
local api_base_url = os.getenv("DEMO_WEBHOOK_URL")
print(api_base_url)
local request_body = string.format("{\
\"type\":\"%s\",\
\"name\":\"%s\",\
\"when\":\"%d\"\
}",
"backend_down",
backend,
when)
local response = httpclient:post{url = api_base_url, body=request_body}
if (response.status ~= 200) then
core.Alert("Error when making request to http endpoint")
end
end
-- this function will be called by event framework each time a server
-- from the chosen backend will be transitioning from UP to DOWN
local function server_down(event, data, mgmt, when)
local server = data.reference -- get a reference to the server
if server == nil then
-- the server has been removed, we cannot fetch
-- (should not happen in our testcase)
return
end
if server:get_proxy():get_srv_act() == 0 then
-- no more active servers within the backend, trigger an alert
backend_is_down(server:get_proxy():get_name(), when)
end
end
core.register_init(function()
-- register server_down function for DOWN event for every server
-- within "test" backend
for srv_name, srv in pairs(core.backends["test"].servers) do
srv:event_sub({"SERVER_DOWN"}, server_down)
end
end)
global
stats socket ipv4@127.0.0.1:9999 level admin
lua-load backend_down_webhook.lua
# by default, the httpclient DNS resolver will use the IPv6 address,
# this changes it to prefer IPv4
httpclient.resolvers.prefer ipv4
defaults
timeout connect 5s
timeout server 5s
timeout client 5s
resolvers default
# we need to define a default resolver section
# for the httpclient in order to resolve hostnames in the URL
nameserver ns1 8.8.8.8:53
backend test
server webserver1 127.0.0.1:8080
server webserver2 127.0.0.1:8081
global
lua-load backend_down_webhook.lua backend_name
local arguments = table.pack(...) -- fetch global arguments from lua-load
core.register_init(function()
-- foreach backend name in arguments
for index,name in ipairs(arguments) do
-- register server_down function for DOWN event for every server
-- within current backend
for srv_name, srv in pairs(core.backends[name].servers) do
srv:event_sub({"SERVER_DOWN"}, server_down)
end
end
end)
-- watch for new server addition
core.event_sub({"SERVER_ADD"}, function(event, data)
local server = data.reference -- get a reference to the server
if server == nil then
return
end
-- as new server has been added dynamically, check if it belongs to
-- one of the tracked backends passed as optional lua-load arguments
for index,name in ipairs(arguments) do
if name == server:get_proxy():get_name() then
-- track the server for DOWN event
server:event_sub({"SERVER_DOWN"}, server_down)
break
end
end
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment