Adding a Node to a Pool
Provisioning systems can dynamically deploy applications across servers, perhaps in reaction to increased server load. This example demonstrates a Control API application that modifies the nodes that a pool balances traffic to.
If the pool is using the “Perceptive” algorithm, load is slowly ramped up on newly introduced nodes in order to gauge their potential performance. This continues until they run at the same speed as the other nodes in the pool. This “Slow Start” capability ensures that new nodes are not immediately overloaded with a large burst of traffic.
Perl Example
#!/usr/bin/perl -w
use SOAP::Lite 0.60;
# This is the url of the Traffic Manager Admin Server
my $admin_server = 'https://username:password@host:9090';
# The pool to edit, and the node to add
my $poolName = "test pool";
my $newNode = "10.100.1.10:80";
my $conn = SOAP::Lite
-> uri('http://soap.zeus.com/zxtm/1.0/Pool/')
-> proxy("$admin_server/soap")
-> on_fault( sub {
my( $conn, $res ) = @_;
die ref $res ? $res->faultstring :
$conn->transport->status; } );
# Get a list of pools
my $res = $conn->getPoolNames();
my @names = @{$res->result};
# Get the nodes for each pool
$res = $conn->getNodes( \@names );
# Build a hash %nodes: pool->[ node list ]
my %nodes;
@nodes{@names} = @{$res->result};
if( !defined $nodes{$poolName} ) {
die "Pool $poolName does not exist...";
}
if( grep { $_ eq $newNode } @{$nodes{$poolName}} ) {
die "Pool $poolName already contains $newNode";
}
# Add one node to the pool
$res = $conn->addNodes( [ $poolName ], [ [ $newNode ] ] );
# We're done! Verify that the node has been added
$res = $conn->getNodes( [ $poolName ] );
my @newnodes = @{${$res->result}[0]};
my $expected = join " ",
sort @{$nodes{$poolName}}, $newNode;
my $actual = join " ", sort @newnodes;
if( $expected ne $actual ) {
die "New node list is '$actual'; expected '$expected'";
}
Notes
This example uses careful error checking to make sure that the Control API methods are not called incorrectly. For example, if a method tries to add a node to a pool that does not exist, a SOAP fault is raised. Perl’s “on_fault” handler is called if this happens.
The example illustrates Perl’s hash slice technique to quickly build an associative array, mapping pool name to a list of nodes:
my $res = $conn->getPoolNames();
my @names = @{$res->result};
$res = $conn->getNodes( \@names );
my %nodes;
@nodes{@names} = @{$res->result};
This is a very easy way to take advantage of the fact that the Control API methods are all bulk-enabled. In other words, they are designed to process lists of objects efficiently.
The listVS example can also use a hash slice, as follows:
my $res = $conn->getVirtualServerNames();
my @names = @{$res->result};
$res = $conn->getEnabled( \@names );
my %enabled;
@enabled{@names} = @{$res->result};
A Control API application can update the configuration by modifying the hash:
# Turn everything off...
foreach my $name( keys %enabled ) {
$enabled{ $name } = 0;
}
It can then bulk-commit the new configuration with a single method call:
$res = $conn->setEnabled(
[ keys %enabled ], [ values %enabled ] );
C# Example
using System;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
public class AllowSelfSignedCerts : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint sp, X509Certificate cert,
WebRequest request, int problem )
{
return true;
}
}
public class addNode {
public static void Main( string [] args )
{
System.Net.ServicePointManager.CertificatePolicy =
new AllowSelfSignedCerts();
string url= "https://host:9090/soap";
string username = "username";
string password = "password";
string poolName = "test pool";
string newNode = "10.100.1.10:80";
try {
Pool p = new Pool();
p.Url = url;
p.Credentials = new NetworkCredential(
username, password );
string[] names = p.getPoolNames();
string[][] allnodes = p.getNodes( names );
string[] nodes = new string[]{};
bool found = false;
for( int i = 0 ; i < names.Length ; i++ ) {
if( names[i] == poolName ) {
nodes = allnodes[i];
found = true;
break;
}
}
if( ! found ) {
Console.WriteLine( "Pool {0} doesn’t exist", poolName );
Environment.Exit( 1 );
}
found = false;
for( int i = 0 ; i < nodes.Length ; i++ ) {
if( nodes[i] == newNode ) {
found = true;
}
}
if( found ) {
Console.WriteLine( "Pool {0} already contains {1}",
poolName, newNode );
Environment.Exit( 1 );
}
// Add one node to the pool
p.addNodes( new string[] { poolName },
new string[][] { new string[] { newNode } } );
} catch ( Exception e ) {
Console.WriteLine( "{0}", e );
}
}
}