How to YAML your load balancer deployment

How to YAML your load balancer deployment

How-Tos Updated on 3 mins

If you read my other posts relating to our v8 API interfaces (follow the links here for parts one and two), but don't want to use either JSON formats as your input format, this is just fine – because we'll be using something different in this post.

Below is the code for a new API interface to take 'YAML Ain't Markup Language' (otherwise known as YAML) and post it to an LBCLI command.

<?php
/*

(c) 2020 Loadbalancer.org - Written by Andruw Smalley

Loadbalancer lbcli YAML lbcli poster /api/v2/yaml
This will just work with any version from v7.6.3 - v8.4.2 
Yes it works with ANY loadbalancer.org appliance which 
works with lbcli, note you will know what you can do in 
each version of lbcli for the API interface to work. 
Remember pre v8 lbcli did not do much!


Example YAML API Usage place in PUT
PUT /var/www/html/api/v2/yaml/index.php 
OR anywhere under /var/www/html/ if you wish.

lbcli:
- action: hostname
function: set
hostname: mole
domain: master.lb.zerodns.co.uk

// YAML IMPLIMENTATION by Andruw Smalley

*/

date_default_timezone_set('Europe/London');

require_once("/etc/loadbalancer.org/api-credentials");
if(!isset($_SERVER["SERVER_ADDR"])) {
    die("call me from a network resource please");
}
putenv("SERVER_ADDR=" . $_SERVER["SERVER_ADDR"]);

if (!isset($username, $password, $apikey)) {
    exit;
} else if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
    header('WWW-Authenticate: Basic realm="API"');
    header('HTTP/1.0 401 Unauthorized');
    echo "lbapi:\n- noway: noyaml\n";
    exit;
} else if ($username == $_SERVER['PHP_AUTH_USER'] && $password == $_SERVER['PHP_AUTH_PW']) {
    if ($_SERVER["HTTP_X_LB_APIKEY"]) {
        if (trim(base64_decode($_SERVER["HTTP_X_LB_APIKEY"])) == $apikey) {

            $fp = fopen('php://input', 'r') or die("  input: failed\n");
            $act = 0;
            while (!feof($fp)) {
                list($key, $value) = explode(":", trim(str_replace("\n", "", fgets($fp))));
                $key = str_replace("- ", "", $key);
                if ($key == "lbcli") {
                    $actok = true;
                    echo "Continuing:\n";
                    continue;
                }
                if ($actok !== true) {
                    echo "noact:\n";
                    return false;
                }
                if ($key == "action") {
                    if (!isset($act)) {
                        $act = -1;
                    }
                    $act++;
                    $lbcli[$act] = "/usr/local/sbin/lbcli --action " . trim($value) . " --method api";
                } else {
                    if (isset($value)) {
                        $lbcli[$act] .= " --" . $key . " " . trim($value);
                    }        
                }          
            }
            fclose($fp);
            $return = yamlout($lbcli);     
        } else {
            header('WWW-Authenticate: Basic realm="YAMLAPI"');
            header('HTTP/1.0 401 Unauthorized');
            echo "lbapi:\"- json: invalid\n";
            die();
        }
    } else {
        header('WWW-Authenticate: Basic realm="API"');
        header('HTTP/1.0 401 Unauthorized');
        echo "lbapi:\n- apikey: failed\n";
        die();
    }
}

function yamlout($lbcli) {
    echo "lbcli:\n";
    foreach ($lbcli as $call) {
        $output    = "[" . shell_exec($cmd . $call) . "]";
        $responses = (json_decode($output, true));
        foreach ($responses as $iteration => $response) {
            $yam[] = $response['itteration']['0']['lbcli']['0'];
        }
    }
    $count   = count($yam);
    $counter = 0;
    while ($counter < $count) {
        foreach ($yam[$counter] as $key => $value) {
            if ($key == "action" || $key == "core") {
                echo "- " . trim($key) . ": " . trim($value) . "\n";
            } else {
                if (!is_array($value)) {
                    echo "  " . trim($key) . ": " . trim($value) . "\n";
                } else {
                    echo "  " . trim($key) . ":\n";
                    if ($value['0']) {
                        $value = $value['0'];
                    } else {
                        $value = $value;
                    }
                    foreach ($value as $okey => $ovalue) {
                        if (!empty($ovalue)) {
                            echo "  - " . trim($okey) . ": " . trim($ovalue) . "\n";
                        }
                    }
                }
            }
        }
        $counter++;
    }
}

The simple interface above will accept YAML but we need something to post the YAML file to the API - this is below:

#!/bin/bash 
# loadbalancer.org api/v2 curl apicall
# Created by Andruw Smalley 
# really simple curl command build from the input, no real validation.
username="loadbalancer"
password="loadbalancer"
port="9443"

while true; do
  case "$1" in
    -l | --loadbalancer ) loadbalancer="$2"; shift 2 ;;
    -u | --username ) username="$2"; shift 2 ;;
    -p | --password ) password="$2"; shift 2 ;;
    -o | --port ) port="$2"; shift 2 ;;
    -y | --yaml ) yaml="$2"; shift 2 ;;
    -a | --apikey ) apikey=$(echo $2 | base64); shift 2 ;;
    * ) break ;;
  esac
done

#if [ $loadbalancer != "" ] || [ $port != "" ] || [ $username != "" ] || [ $password != "" ] || [ $yaml != "" ] || [ $apikey != "" ]; then
	curl -u ${username}:${password} -X POST  \
	     --header "X_LB_APIKEY: ${apikey}" \
	     --data-binary @${yaml} https://${loadbalancer}:${port}/api/v2/yaml/ -k
	exit $?
#else
#	echo "./apicall.sh --loadbalancer 192.168.2.21 --port 9443 --username loadbalancer --password loadbalancer --yaml /path/to/yaml.yaml --apikey eP68pvSMM8dvn051LL4d35569d438ue0"
#	echo "Defaults are set for username,password,port so you only really need --yaml --apikey and --loadbalancer if you have defaults"
#fi

With this, we now have the YAML interface and a method to post the contents! So all that's left is to share all the API syntax in YAML format.

A single YAML code block example layout is below:

lbcli:
-  action: api
   function: enable
   username:
   password:
   apikey:

And if you wish to run more than one - action: at a time simply add another action without re-declaring lbcli:

lbcli:
-  action: api
   function: enable
   username:
   password:
   apikey:
-  action: api
   function: disable   

So there we have it - how to YAML our load balancer, plus the ability to add your YAML file format to the API, should you choose to.

We've uploaded the YAML interface code to GitHub, as well as the YAML library.