Version 2.1 of the HAProxy Data Plane API expands support to all available request and response actions, adds Lua actions, and improves file handling.
A year ago, we introduced version 1.0 of the HAProxy Data Plane API, enabling you to configure your HAProxy load balancers remotely through a modern RESTful HTTP API. That first version of the API focused on the essential behaviors for creating frontend proxies, backend server pools, ACLs and traffic switching rules. The list of features has continued to expand since then, culminating in this most recent version, 2.1.
Version 2.1 follows up on the recent 2.0 release and puts the focus on request and response actions that allow HAProxy to shape traffic, modify requests, track behavior, and drop connections dynamically. This includes custom Lua actions that you define and load into HAProxy. This version also accumulates bug fixes and other improvements made since the initial release and we have improved how the file handling in the HAProxy Data Plane API works, making it more robust. We’ll cover what changed and the issues we faced there.
Another key feature added was serving an OpenAPI v3-compatible version of the specification together with the v2 version (formerly known as Swagger). The HAProxy Data Plane API is built using the Open API 2.0 specification, and on its /specification endpoint it serves that version in JSON format. You can use that endpoint to build your own client libraries and then consume the API in any language you would like. You’ll find some helpful examples of how to do that in our blog post HAProxy Go Packages Ecosystem. Since the initial release, the Open API specification has moved to version 3.0 and some helpful tools for generating code, creating documentation, and publishing simple UIs rely on that newer version. To support people wishing to use these tools, and to move the HAProxy Data Plane API forward, it now serves a v3-compatible specification at the /specification_openapiv3 endpoint, in the JSON format.
Request and Response Actions
For this version, we set our focus on expanding the http-request
and http-response
directives to support all available actions. This unlocks some of the most powerful capabilities of HAProxy, including the ability to set the priority of different requests, change the attributes of an HTTP message, silently drop malicious users, and track clients across requests.
The following actions are now supported on the /services/haproxy/configuration/httprequestrules endpoints:
lua.<action>
The following actions are now supported on the /services/haproxy/configuration/httpresponserules endpoints:
lua.<action>
Lua Support
One of the advantages of using HAProxy is having the ability to extend the load balancer with your own, custom, Lua code. With this version of the API, you can load Lua modules at startup and insert your Lua actions into the request and response pipelines. You can learn more about how to integrate HAProxy with Lua by reading our blog post 5 Ways to Extend HAProxy with Lua. If your version of HAProxy is compiled with Lua support, you can use the API’s /services/haproxy/configuration/global endpoint to add lua-load
directives to the global
section of your configuration. Here’s an example:
$ curl -X PUT \ | |
'http://127.0.0.1:5555/v2/services/haproxy/configuration/global?version=1' \ | |
-H 'authorization: Basic YWRtaW46YWRtaW4=' \ | |
-H 'content-type: application/json' \ | |
-d '{ | |
"lua_loads": [ | |
{ | |
"file": "/etc/haproxy/foo.lua" | |
} | |
] | |
}' |
We’ve added support for configuring HAProxy to call your Lua action with the http-request
, tcp-request
, http-response
and tcp-response
directives. So, you can invoke your Lua action like this, which places an http-request lua
line into a frontend
named http-1:
$ curl -X POST \ | |
'http://127.0.0.1:5555/v2/services/haproxy/configuration/http_request_rules?parent_type=frontend&parent_name=http-1&version=1' \ | |
-H 'authorization: Basic YWRtaW46YWRtaW4=' \ | |
-H 'content-type: application/json' \ | |
-d '{ | |
"index": 0, | |
"type": "lua", | |
"lua_action": "checkip", | |
"lua_params": "127.0.0.1 5000" | |
}' |
This would produce a configuration like this:
global | |
lua-load /etc/haproxy/foo.lua | |
frontend http-1 | |
http-request lua.checkip 127.0.0.1 5000 | |
# other settings... |
Robust File Handling
On some rare occasions, the Data Plane API was truncating the resulting HAProxy configuration file down to zero bytes after a transaction was committed. This was happening because the file-copy from the transaction file to the actual configuration file wasn’t truly atomic, as there were two actions being executed. First, we were creating the file, which happened when the code called the Golang method os.Create
, and then we were copying the updated contents to the file with io.Copy
. Calling os.Create
truncates the destination file, but in some cases, something went wrong and io.Copy
was never called.
Identifying this we switched the HAProxy config-parser library to use the google/renameio package to ensure the atomicity of the operation. Now the Data Plane API uses the newer version of the config-parser library, which writes files using renameio.WriteFile
. Also, we are no longer copying from the transaction file to the destination HAProxy configuration file, but are instead using the in-memory state of the config-parser to write the configuration file. This way, we eliminate the issue of moving files across different filesystems.
Other Minor Changes
In addition to the changes mentioned above, the 2.1 version includes bug fixes that were added in minor releases since the 2.0 version and other improvements.
Added
alpn
andproxy-v2-options
fields to the /services/haproxy/configuration/server endpointAdded
ssl-default-bind-ciphersuites
andssl-default-server-ciphersuites
to the /services/haproxy/configuration/global endpointYou can now fetch and work with map files that are located outside the configured
maps-dir
directory on the /services/haproxy/runtime/maps endpoint
Contributors
We’d like to thank the code contributors who helped make this version possible:
Contributor | Area |
Amel Husić | FEATURE BUG |
Andjelko Iharos | FEATURE |
Daniel Corbett | BUG |
Jared Curtis | BUG |
Kashif Minhaj | BUG |
Marko Juraga | BUILD FEATURE BUG |
Robert Maticevic | FEATURE |
Stefan Scheglmann | FEATURE |
Zlatko Bratkovic | FEATURE BUG |
Conclusion
The HAProxy Data Plane API version 2.1 expands the set of features to cover more of the dynamic capabilities that are unique to HAProxy, including the ability to load and call your own Lua actions. It includes several bug fixes, including a bug that truncated the configuration file under some conditions. The API continues to get better thanks to the active community surrounding it. If you’d like to get involved, head over to our GitHub repository to learn more!
Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.