Stingray provides a SOAP-based Control API, with an interface clearly defined using a collection of WSDL files. Regrettably, Perl's SOAP::Lite implementation completely ignores WSDL specifications, making the task of communicating with a SOAP service much harder than it should be. This article describes how to call Stingray's SOAP methods and use SOAP enumerations and structures with SOAP::Lite.
A method can be invoked from a SOAP::Lite connection object that specifies the appropriate interface:
getVirtualServerNames()
Gets the names of all the configured virtual servers.
Prototype:
String[] getVirtualServerNames()
Call it as follows:
# Create a connection object that uses the VirtualServer interface
my $conn = SOAP::Lite
-> ns('http://soap.zeus.com/zxtm/1.0/VirtualServer/')
-> proxy("$admin_server/soap");
# You can invoke any of the methods of the VirtualServer interface
my $res = $conn->getVirtualServerNames();
my @names = @{$res->result};
If you need to use several interfaces (for example, VirtualServer and Pool), you will need to construct a SOAP::Lite connection object for each.
If you attempt to invoke a method that does not exist for the interface, the method call will fail and the on_fault fault handler (if specified) will be called.
A Structure is a complex datatype that contains several parameters. For example, the key configuration settings for a Virtual Server are represented by a VirtualServer.BasicInfo structure that defines the port, protocol and default pool for that Virtual Server:
VirtualServer.BasicInfo
This structure contains the basic information for a virtual server. It is used when creating a server, or modifying the port, protocol or default pool of a server.
struct VirtualServer.BasicInfo {
# The port to listen for incoming connections on.
Integer port;
# The protocol that this virtual server handles.
VirtualServer.Protocol protocol;
# The default pool that traffic to this virtual server will go to.
String default_pool;
}
This structure contains three elements; an Integer (the port number), an Enumeration (VirtualServer.Protocol – the protocol) and a string (the name of the default pool). The method VirtualServer.addVirtualServer() takes a VirtualServer.BasicInfo structure which can be constructed as follows:
my $basicInfo = {
port => '443',
protocol => 'https',
default_pool => 'Server Pool 1'
};
$res = $conn->addVirtualServer( [ $vsName ], [ $basicInfo ] );
If you call the method VirtualServer.getBasicInfo(), it will return a corresponding array of VirtualServer.BasicInfo structures that can be unpacked as follows:
$res = $conn->getBasicInfo( [ $vsName ] );
my $r = @{$res->result}[0];
print "Virtual Server $vsName:\n";
print " port $r->{port}, protocol $r->{protocol}, pool $r->{default_pool}\n";
However, to get this example working end-to-end, you first need to understand how Perl interperts enumeration types (such as the protocol).
An Enumeration is a particular datatype with a restricted, named set of values. For example, a Pool has a limited set of load balancing algorithms that are represented by the Pool.LoadBalancingAlgorithm enumeration. The enumeration is defined as follows:
Pool.LoadBalancingAlgorithm
enum Pool.LoadBalancingAlgorithm {
roundrobin, # Round Robin
wroundrobin, # Weighted Round Robin
cells, # Perceptive
connections, # Least Connections
wconnections, # Weighted Least Connections
responsetimes, # Fastest Response Time
random # Random node
}
The Pool interface contains two methods that use that enumeration:
getLoadBalancingAlgorithm( names )
Get the load balancing algorithms that each of the named pools uses.
Pool.LoadBalancingAlgorithm[] getLoadBalancingAlgorithm(
String[] names
)
setLoadBalancingAlgorithm( names, values )
Set the load balancing algorithms that each of the named pools uses.
void setLoadBalancingAlgorithm(
String[] names
Pool.LoadBalancingAlgorithm[] values
)
Perl’s SOAP::Lite library encodes enumerations in SOAP requests, so you can use them in a literal fashion:
$conn->setLoadBalancingAlgorithm( [ $poolName ], ['connections'] );
In a SOAP response, you need to provide a custom Deserializer so that the SOAP::Lite library can convert the values in the SOAP response into appropriate internal representations (i.e. literal strings):
BEGIN {
package MyDeserializer;
@MyDeserializer::ISA = 'SOAP:
eserializer';
sub typecast {
my( $self, $val, $name, $attrs, $children, $type ) = @_;
if( $type && $type =~ [email protected]http://soap.zeus.com/zxtm/@ ) {
return $val;
}
return undef;
};
}
my $conn = SOAP::Lite
-> ns('http://soap.zeus.com/zxtm/1.0/Pool/')
-> proxy("$admin_server/soap")
-> deserializer( MyDeserializer->new );
The following code sample illustrates how to use Control API methods that use Enumerations:
#!/usr/bin/perl -w
use SOAP::Lite 0.6;
# Provide our own Deserializer to deserialize enums correctly
BEGIN {
package MyDeserializer;
@MyDeserializer::ISA = 'SOAP:
eserializer';
sub typecast {
my( $self, $val, $name, $attrs, $children, $type ) = @_;
if( $type && $type =~ [email protected]http://soap.zeus.com/zxtm/@ ) {
return $val;
}
return undef;
};
}
# This is the url of the Stingray admin server
my $admin_server = 'https://username
[email protected]:9090';
# The pool to edit
my $poolName = $ARGV[0] or die "No pool specified";
my $conn = SOAP::Lite
-> ns('http://soap.zeus.com/zxtm/1.0/Pool/')
-> proxy("$admin_server/soap")
-> deserializer( MyDeserializer->new )
-> on_fault( sub {
my( $conn, $res ) = @_;
die ref $res?$res->faultstring:$conn->transport->status; } );
# Get the load balancing algorithm
my $res = $conn->getLoadBalancingAlgorithm( [ $poolName ] );
my $alg = @{$res->result}[0];
print "Pool $poolName uses load balancing algorithm $alg\n";
# Change the algorithm to least connections, and check it worked
$conn->setLoadBalancingAlgorithm( [ $poolName ], ['connections'] );
$res = $conn->getLoadBalancingAlgorithm( [ $poolName ] );
print "Algorithm has been changed to @{$res->result}[0]\n";
# Now change it back again
$conn->setLoadBalancingAlgorithm( [ $poolName ], [ $alg ] );
$res = $conn->getLoadBalancingAlgorithm( [ $poolName ] );
print "Algorithm changed back to @{$res->result}[0]\n";
The following code sample illustrates how to create a virtual server and manage the BasicInfo structure:
#!/usr/bin/perl -w
use SOAP::Lite 0.6;
# Provide our own Deserializer so to deserialize enums correctly
BEGIN {
package MyDeserializer;
@MyDeserializer::ISA = 'SOAP:
eserializer';
sub typecast {
my( $self, $val, $name, $attrs, $children, $type ) = @_;
if( $type && $type =~ [email protected]http://soap.zeus.com/zxtm/@) {
return $val;
}
return undef;
};
}
# This is the url of the Stingray admin server
my $admin_server = 'https://user
[email protected]:9090';
# The virtual server to create
my $vsName = $ARGV[0] or die "No vs specified";
my $conn = SOAP::Lite
-> ns('http://soap.zeus.com/zxtm/1.0/VirtualServer/')
-> proxy("$admin_server/soap")
-> deserializer( MyDeserializer->new )
-> on_fault( sub {
my( $conn, $res ) = @_;
# Construct the basic info structure
my $basicInfo = {
port => '443',
protocol => 'https',
default_pool => 'discard'
};
$res = $conn->addVirtualServer( [ $vsName ], [ $basicInfo ] );
$res = $conn->getBasicInfo( [ $vsName ] );
my $r = @{$res->result}[0];
print "Virtual Server $vsName:\n";
print " port $r->{port}, protocol $r->{protocol}, pool $r->{default_pool}\n";
Stingray's Control API Documentation (Stingray Product Documentation) describes how you can communicate with Stingray in a language-independent manner (so long as your application has a SOAP library). The examples above should help kick-start your next Stingray / Perl development project. Good luck!