Announcing HAProxy Data Plane API 2.1
Version Update

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:

The following actions are now supported on the  /services/haproxy/configuration/httpresponserules endpoints:

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-requesttcp-requesthttp-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 and proxy-v2-options fields to the /services/haproxy/configuration/server endpoint

  • Added ssl-default-bind-ciphersuites and ssl-default-server-ciphersuites to the /services/haproxy/configuration/global endpoint

  • You 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.