Set, modify and hot load haproxy configuration from node.
Functionality and code lifted and adapted from thalassa=aqueduct.
You can run this module standalone (npm install -g node-haproxy; node-haproxy --ipc
) and
communicate with it using ipc (var ipcClient = require ('node-haproxy/src/ipc-client'
)
or use the api directly (var haproxy = require('node-haproxy'
).
In both cases it will fire up a haproxy instance which you can query and modify programmatically.
When modifying or adding/removing front and backends programmatically haproxy is reconfigured on the fly. Back and frontends are persisted between restarts of the node process.
Changes are saved to a leveldb.
When no options are passed in, the included haproxy executable (v1.5) is used. The leveldb and persisted data is stored by default in the module's folder. Which means that on updating or reinstalling the module the data is wiped.
Locations of the leveldb, template haproxy.cfg file and persisted info file can be set using options, amongst some more settings relating to haproxy.
Paraphrased from the original readme:
Node-haproxy does not try to obfuscate HAProxy, and it's important to know the fundamentals of how HAProxy works to understand node-haproxy. The API mirrors HAProxy's semantics. The HAProxy documentation contains a wealth of detailed information.
-
Frontends - A "frontend" section describes a set of listening sockets accepting client connections.
-
Backends - A "backend" section describes a set of servers to which the proxy will connect to forward incoming connections.
-
Members/Servers - node-haproxy calls the servers that backends route to "members". In other words, members of a backend pool of servers.
-
Config file - At startup, HAProxy loads a configuration file and never looks at that file again. node-haproxy manages this by re-templating a new config file and gracefully restarting the HAProxy process.
-
Stats Socket - a UNIX socket in stream mode that will return various statistics outputs and even allows some basic configuration tweaking like enabling and disabling existing backend members, setting weights, etc.
./node_modules/.bin/node-haproxy --help
Options:
--haproxySocketPath path to Haproxy socket file
--haproxyPidPath path to Haproxy pid file
--haproxyCfgPath generated Haproxy config location
--templateFile template used to generate Haproxy config
--persistence directory to save configuration
--dbPath filesystem path for leveldb
--sudo use sudo when starting haproxy
--which path for haproxy, set to 'system' to look for it, otherwise the included haproxy (v1.5) is used
--ipc start up ipc server
The following functions can be invoked on the required node-haproxy module or
using the ipc-client (ipcClient(functionName, args
), which uses promises:
Don't forget to call ipcClient.close() if you want to stop the node process..
Example of using the ipc-client:
ipcClient('getFrontends', [])
.when(
function(result) {
console.log("Frontends\n", result);
return ipcClient('getBackends', []);
})
.when(
function(result) {
console.log("Backends\n", result);
ipcClient.close();
},
function(error) {
console.log("Error\n", error);
ipcClient.close();
}
);
Returns Array of frontend
objects for all of the frontends configured
For example:
[{
"id": "frontend/myapp",
"_type": "frontend",
"key": "myapp",
"bind": "*:8080,*:80",
"backend": "live",
"mode": "http",
"keepalive": "default",
"rules": [{
"type": "header",
"header": "host",
"operation": "hdr_dom",
"value": "staged.myapp.com",
"backend": "staged"
}],
"natives": []
}]
Gets a specific frontend by key
.
Create or update a frontend
by key
.
{
"bind": "10.2.2.2:80,*:8080" // IP and ports to bind to, comma separated, host may be *
, "backend": "foo" // the default backend to route to, it must be defined already
, "mode": "tcp" // default: http, expects tcp|http
, "keepalive": "close" // default: "default", expects default|close|server-close
, "rules": [] // array of rules, see below
, "natives": [] // array of strings of raw config USE SPARINGLY!!
}
Delete a specific frontend by key
.
Returns Array of backend
objects for all of the backends configured
For example:
[{
"id": "backend/live",
"_type": "backend",
"key": "live",
"type": "dynamic",
"name": "classroom-ui",
"version": "1.0.0",
"balance": "roundrobin",
"host": null,
"mode": "http",
"members": [{
"name": "myapp",
"version": "1.0.0",
"host": "10.10.240.121",
"port": 8080,
"lastKnown": 1378762056885,
"meta": {
"hostname": "dev-use1b-pr-01-myapp-01x00x00-01",
"pid": 17941,
"registered": 1378740834616
},
"id": "/myapp/1.0.0/10.10.240.121/8080"
},
{
"name": "myapp",
"version": "1.0.0",
"host": "10.10.240.80",
"port": 8080,
"lastKnown": 1378762060226,
"meta": {
"hostname": "dev-use1b-pr-01-myapp-01x00x00-02",
"pid": 18020,
"registered": 1378762079883
},
"id": "/myapp/1.0.0/10.10.240.80/8080"
}],
"natives": []
}]
Gets a specific backend
by key
.
Create or update a backend
by key
.
{
"type" : "dynamic|static"
, "name" : "foo" // only required if type = dynamic
, "version" : "1.0.0" // only required if type = dynamic
, "balance" : "roundrobin|source" // defaults to roundrobin
, "host" : "myapp.com" // default: undefined, if specified request to member will contain this host header
, "health" : { // optional health check
"method": "GET" // HTTP method
, "uri": "/checkity-check" // URI to call
, "httpVersion": "HTTP/1.1" // HTTP/1.0 or HTTP/1.1 `host` required if HTTP/1.1
, "interval": 5000 // period to check, milliseconds
}
, "mode" : "http|tcp" // default: http
, "natives": [] // array of strings of raw config USE SPARINGLY!!
, "members" : [] // if type = dynamic this is dynamically populated based on role/version subscription
// otherwise expects { host: '10.10.10.10', port: 8080}
}
Delete a specific backend
by key
.
Update a backend
s role
and version
{
"name": "myapp"
, "version": "1.1.0" // version to route to
}
name
is actually optional. You may also just send the version
:
{
"version": "1.1.0"
}
Return the last know generated HAProxy config file contents that were written to the location of opts.haproxyCfgPath
.
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
daemon
maxconn 4096
user haproxy
group haproxy
stats socket /tmp/haproxy.status.sock user appuser level admin
defaults
log global
option dontlognull
option redispatch
retries 3
maxconn 2000
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen stats :1988
mode http
stats enable
stats uri /
stats refresh 2s
stats realm Haproxy\ Stats
stats auth showme:showme
frontend myapp
bind *:8080,*:80
mode http
default_backend live
option httplog
option http-server-close
option http-pretend-keepalive
acl header_uv7vi hdr_dom(host) myapp-staged.com
use_backend staged if header_uv7vi
backend live
mode http
balance roundrobin
server live_10.10.240.121:8080 10.10.240.121:8080 check inter 2000
server live_10.10.240.80:8080 10.10.240.80:8080 check inter 2000
backend staged
mode http
balance roundrobin
server staged_10.10.240.174:8080 10.10.240.174:8080 check inter 2000
server staged_10.10.240.206:8080 10.10.240.206:8080 check inter 2000
There are currently 3 types of rules that can be applied to frontends: path
, url
, and header
.
Path rules support path
, path_beg
, and path_reg
HAProxy operations
{
"type": "path"
, "operation": "path|path_beg|path_reg"
, "value": "favicon.ico|/ecxd/|^/article/[^/]*$"
, "backend": "foo" // if rule is met, the backend to route the request to
}
Url rules support url
, url_beg
, and url_reg
HAProxy operations
{
"type": "url"
, "operation": "url|url_beg|url_reg"
, "value": "/bar" // value for the operation
, "backend": "bar" // if rule is met, the backend to route the request to
}
Header rules support hdr_dom
with a entire value at this point
{
"type": "header"
, "header": "host" // the name of the HTTP header
, "operation": "hdr_dom"
, "value": "baz.com"
, "backend": "baz" // if rule is met, the backend to route the request to
}
The natives property is an end around way to insert raw lines of config for front ends and backends. Use them sparingly but use them if you need them.
- thrown exceptions are are not handled in api.js and dependencies
- remove health checks/roles/version leftover from Aqea