How to automate legacy load balancer deployments

Automation Published on 8 mins Last updated

UPDATE: if you're automating our load balancer, and are running version 8.4.1 or higher, please refer to our newer automation API blog. If you're on a version of our product earlier than 8.4.1, read on for our recommended automation method.

Automation is very important for many organisations, which is why it's one of the core features of our upcoming V9 release.

Version 9 is being built from the ground up to be API driven, so all functionality and features available in the Web User Interface (WUI) will be catered for. While V9 is certainly on the horizon, it's still a little way off and so there is the question "What can we do while still using V8?".

For those running V8, the Loadbalancer.org appliance already has options to facilitate automated deployment and management. You may already be aware of the existing lbcli command and API. The lbcli command is a wrapper around the WUI functions and the API is another wrapper around lbcli. Both allow commands to be sent to your Loadbalancer.org appliance to create, edit, delete new configurations or perform maintenance tasks outside of the WUI.

Example adding a L4 Virtual Service:

lbcli --action add-vip --layer 4 --vip theVipName \
--ip 192.168.100.123 --ports 80 --forwarding gate --protocol tcp

The same but as a JSON API post (apicall.json):

{
   "auth":{
      "apikey":"eP68pvSMM8dvn051LL4d35569d438ue0"
   },
   "action":[
      {
         "command":"add-vip"
      }
   ],
   "syntax":[
      {
         "layer":"4",
         "vip":"theVipName",
         "ip":"192.168.100.123",
         "ports":"80",
         "forwarding":"gate",
         "protocol":"tcp"
      }
   ]
}

Using the JSON example above, if you save it to a file call "apicall.json" and use the curl example below. You can also use these examples with your deployment and automation tools such as Puppet.

curl -u loadbalancer:loadbalancer -X POST -d @apicall.json \
https://192.168.100.100:9443/api/ --header Content-Type:application/json -k

So, although V9 is still a while off, we actually do have some support for automation already! This covers around 98% of product functionality or most of the features found under the "Cluster Configuration" menu of the appliance. Both lbcli and the API can be configured to provide single operation actions such as adding a VIP/RIP or reloading/restarting a system service, or it can be utilised to process multiple actions in a single command such as adding a VIP and multiple RIPs. It is possible to batch create a new Layer 4 or Layer 7 Virtual Service with all the Real Servers which are needed, set the state of those servers and even add Headers and ACL's as you go, all without looking at the WUI at all.

Adding a VIP and multiple RIP's in a single command:

lbcli --action add-vip --layer 4 --vip theVipName --ip 192.168.100.123 \
--ports 80 --forwarding gate --protocol tcp --action add-rip \
--vip theVipName --rip FirstRIP --ip 192.168.100.125 --weight 100

The same but as a JSON API post:

{
   "auth":{
      "apikey":"eP68pvSMM8dvn051LL4d35569d438ue0"
   },
   "action":[
      {"command":"add-vip"},
      {"command":"add-rip"}
   ],
   "syntax":[
      {
         "layer":"4",
         "vip":"theVipName",
         "ip":"192.168.100.123",
         "ports":"80",
         "forwarding":"gate",
         "protocol":"tcp"
      },
     {
         "vip":"theVipName",
         "rip":"FirstRIP",
         "ip":"192.168.100.125",
         "weight":"100"
      }
   ]
}

While this is a great step forward, we still have some parts of the product not supported by lbcli/API and for many of these omissions, you can instead use a curl command allowing you to do things such as upload SSL certificates or create an SSL termination:

Create a curl script like so (UploadCertificate.sh):
UPLOAD PEM/PFX

#!/bin/bash
# upload pem file
curl -s -u loadbalancer:loadbalancer -X POST \
--form cert_action=upload \
--form label=$1 \
--form upload_type=$2 \
--form ssl_upload_file=@$3 \
--form pfx_pass=$5 \
https://$4:9443/lbadmin/config/sslcert.php?action=newcert \
-k | grep -c success

Variable explained:

$1=SSLCertLabel
$2=pem/pfx
$3=/full/path/to/sslcert.(pem:pfx)
$4=IP of loadbalancer.org Master appliance.
$5=pfx_password only if cert upload if pfx its not needed otherwise.

Assuming you made the above script and saved it as "UploadCertificate.sh". You can then execute that script with one of the syntax examples below.

To upload a PEM Certificate:

./UploadCertificate.sh example.com pem \
/home/username/ssl/example.com.pem  172.31.20.10

To upload a PFX Certificate with a password:

./UploadCertificate.sh example.com pfx \
/home/username/ssl/example.com.pfx  172.31.20.10 pfxPa55w0rd

The output will be a 0 or a 1 where 1 is success

Now that you have an uploaded PEM or PFX file, you may wish to create an SSL Termination to use the new uploaded certificate. This can be done with lbcli/API already but also, optionally, it could be done with a curl command. Below is the lbcli, API and curl examples of this action for comparison:

LBCLI:

lbcli --action termination --type stunnel --function add --vip example_sslterm_vip \
--ip 172.31.20.99 --port 443 --backend_ip 172.31.20.99 \
--backend_port 80 --sslcert example.com

API JSON file:

{
   "auth":{
      "apikey":"eP68pvSMM8dvn051LL4d35569d438ue0"
   },
   "action":[
      {
         "command":"termination"
      }
   ],
   "syntax":[
      {
         "type":"stunnel",
         "function":"add",
         "vip":"example_sslterm_vip",
         "ip":"172.31.20.99",
         "port":"443",
         "backend_ip":"172.31.20.99",
         "backend_port":"80",
         "sslcert":"example.com"
      }
   ]
}

Then, post the created JSON file using curl:

curl -u loadbalancer:loadbalancer -X POST -d @apicall.json \
https://172.31.20.10:9443/api/ --header Content-Type:application/json -k

Curl:

curl -u loadbalancer:loadbalancer -X POST \
--form label="example_sslterm_vip" \
--form ssl_cert="example.com" \
--form vip="172.31.20.99" \
--form vip_port="443" \
--form backend="172.31.20.99" \
--form backend_port="80" \
--form ciphers="ALL" \
--form terminator="stunnel" \
--form en_xHTTP="on" \
--form rewritelocation="on" \
--form honour_cipher_order="on" \
--form allowciphernegotiation="on" \
--form disable_sslv2="on" \
--form disable_sslv3="on" \
--form disable_tlsv1="on" \
--form stunnel_renegotiation="on" \
--form stunnel_timetoclose="0" \
--form stunnel_proxy="off" \
--form stunnel_proxy_bind="None" \
--form addphys="on" \ 
"https://172.31.20.10:9443/lbadmin/config/ssl.php?action=adddata" -k

As of v8.3.4 the syntax changed to include haproxy_proxy_bind features and linking of SSL Terminations to Layer7 VIP's as seen below.

curl -u loadbalancer:loadbalancer -X POST \
--form label="example_sslterm_vip" \
--form haproxy_ssl_link="custom" \ 
--form vip="172.31.20.99" \
--form vip_port="443" \
--form backend="172.31.20.99" \
--form backend_port="80" \
--form sslmode="high" \
--form ssl_cert="server" \
--form ciphers="ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256" \
--form disablesslv3="on" \
--form disabletlsv1="on" \
--form terminator="stunnel" \
--form disablesslv2="on" \
--form rewritelocation="on" \
--form honour_cipher_order="on" \
--form allowciphernegotiation="0" \
--form empty_fragments="on" \
--form stunnel_delay_dns="on" \
--form servercipherorder="on" \
--form stunnel_renegotiation="on" \
--form stunnel_timetoclose="0" \
--form stunnel_source "192.168.100.110" \
--form stunnel_proxy_bind="None" \
--form go="Update" \
"https://172.31.20.10:9443/lbadmin/config/ssl.php?action=adddata" -k

The "haproxy_ssl_link" is a combination of "VIP_Name^ip^port" where the IP and port are the backend linked Layer7 VIP or "custom" where the backend and backend_port should be defined.

If the haproxy_ssl_link is defined then the backend and backned_port can be ommited.

Backup the loadbalancer.org appliance to a remote file location using bash and curl.

#!/bin/bash
# set -x
set -e

#################################################################
# Loadbalancer.org (c) 2018
#
# bash script to perform backup on a Loadbalancer.org appliance.
# 
# Written by Neil Stone
# Feel free to adapt and enhance
# copy backup.sh /usr/local/bin
#
# chmod 755 backup.sh
# to use type "backup.sh 192.168.100.100 loadbalancer"
#
#################################################################

if [ $# -ne 2 ]; then
    echo "Usage: ${0} <IP> <WebUI-Password>"
    exit 1
fi

# WebUI credentials
USERNAME="loadbalancer"
PASSWORD=${2}
HOST=${1}
PROTO="https" # http or https

# Path to output the backup files to
FILEPATH="/var/backup/loadbalancer"

### Shouldn't need to edit below here.

TIMESTAMP="$(date +%Y%m%d)"

if [ ${PROTO} = "https" ] ; then
    PORT="9443"
else
    PORT="9080"
fi

CURLCMD="curl -s -k -u ${USERNAME}:${PASSWORD} ${PROTO}://${HOST}:${PORT}/lbadmin/config"

if [ ! -d ${FILEPATH}/${TIMESTAMP} ] ; then
	mkdir -p ${FILEPATH}/${TIMESTAMP}
fi

${CURLCMD}/getxmlconfig.php > ${FILEPATH}/${TIMESTAMP}/lb_config.xml
${CURLCMD}/getfirewall.php > ${FILEPATH}/${TIMESTAMP}/rc.firewall
${CURLCMD}/getcerts.php > ${FILEPATH}/${TIMESTAMP}/loadbalancer_ssl_certs.tar.gz
${CURLCMD}/gethaproxyman.php > ${FILEPATH}/${TIMESTAMP}/haproxy_manual.cfg

All this is very linux centered and as such I will start expanding this blog with a couple of Windows(r) PowerShell scripts.

First how to backup your configuration using PowerShell

#######################################################################
# loadbalancer.org (c)2018 PowerShell backup script
# 
# Written by Andrew Smalley
# Email support added by Neil Stone
# Feel free to adapt and enhance
#
# This script requires PowerShell 3.0 If you do not have that
# Please download and install from the location below
#
# https://www.microsoft.com/en-gb/download/confirmation.aspx?id=34595&6B49FDFB-8E5B-4B07-BC31-15695C5A2143=1
#
#######################################################################

$location="c:\loadbalancer.org\backups"
$user = "loadbalancer"
$pass = "loadbalancer"
$ip = "192.168.1.1"
#
$sendemail="yes" 
# yes = send backup via email, notify = notify only via email
# no = no email
$mailfrom="mailfrom@domain.com"
$mailto="mailto@domain.com"
$smtpserver="mail.domain.com"

# You should not edit below this line....
##########################################################################

$protocol="http"  # HTTPS Is not currently supported
$timestamp = Get-Date -format "yyyyMMdd"

if($protocol -Match "http") {
    $port="9080" 
} else {
    $protocol="https" 
    $port="9443"
}

$url = "${protocol}://${ip}:${port}/lbadmin/config"

[system.io.directory]::CreateDirectory("${location}\${timestamp}")

$pair = "${user}:${pass}"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{ Authorization = $basicAuthValue }

Invoke-WebRequest -Uri "${url}/getxmlconfig.php" -OutFile "${location}\${timestamp}\lb_config.xml" -Headers $headers
Invoke-WebRequest -Uri "${url}/getfirewall.php" -OutFile "${location}\${timestamp}\rc.firewall" -Headers $headers 
Invoke-WebRequest -Uri "${url}/getcerts.php" -OutFile "${location}\${timestamp}\loadbalancer_ssl_certs.tar.gz" -Headers  $headers
Invoke-WebRequest -Uri "${url}/gethaproxyman.php" -OutFile "${location}\${timestamp}\haproxy_manual.cfg" -Headers $headers 

if($sendemail -Match "yes") {
    Get-ChildItem "${location}\${timestamp}" | Where {-NOT $_.PSIsContainer} | foreach {$_.fullname} | Send-MailMessage -From ${mailfrom} -To ${mailto} -Subject "Backup report - ${timestamp}" -Body "Attached is today's backup" -SmtpServer ${smtpserver}
} elseif($sendemail -Match "notify") {
    Send-MailMessage -From ${mailfrom} -To ${mailto} -Subject "Backup report - ${timestamp}" -Body "Today's backup has finished. It is available at ${location}\${timestamp}" -SmtpServer ${smtpserver}
} else {
    Write-Host "Loadbalancer.org appliance backed to ${location}\${timestamp}"
}

The next PowerShell example shows you how to interact with LBAPI

# Powershell wrapper for LBAPI

$user = "loadbalancer"
$pass = "loadbalancer"
$ip = "192.168.100.100"
$pair = "${user}:${pass}"
$jsonfile = "c:\add-vip.json"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$headers = @{ Authorization = $basicAuthValue }
$json = Get-Content $jsonfile  -Raw

Invoke-WebRequest -Uri "http://${ip}:9080/api/" -Method Post -Body $json -ContentType "application/json" -Headers $headers

An example JSON HTTP Post is below to add a vip however all the JSON example above apply to the PowerShell script

{
    "auth": {
        "apikey": "eP68pvSMM8dvn051LL4d35569d438ue0"
},
    "action": [{
        "command": "add-vip"
    }],
    "syntax": [{
        "layer": "7",
        "vip": "VIP1",
        "ip": "192.168.100.100",
        "ports": "80",
        "mode": "http"
    }]
}

Hopefully, this gives you an idea of what you can do with the Loadbalancer.org appliance outside the WUI using simple HTTP POST's with the LBCLI / API examples.

For individual help and advice on each action just use:

lbcli --help <action|lbcli|help|about>

If you would like to know more please do not hesitate to open a ticket or e-mail support@loadbalancer.org.