cancel
Showing results for 
Search instead for 
Did you mean: 

Pulse Secure vADC

Sort by:
The following code uses Stingray's RESTful API to add a pool.   The code is written in Python. This program creates a new pool, "pytest", first doing a GET to make sure the pool doesn't already exist, and if the pool doesn't exist, the pool is created by doing a PUT with just the minimum data need to create a pool.  In this case the program creates a properties dictionary with just one node.  All other values will get default values when Stingray creates the pool.   addpool.py   #! /usr/bin/env python import requests import json import sys poolName = 'pytest' pool = { 'properties' : { 'basic' : { 'nodes' : [ '192.168.168.135:80'] } } } url = 'https://stingray.example.com:9070/api/tm/1.0/config/active/pools/' + poolName jsontype = {'content-type': 'application/json'} client = requests.Session() client.auth = ('admin', 'admin') client.verify = False try: #First see if the pool already exists response = client.get(url) except requests.exceptions.ConnectionError: print "Error: Unable to connect to " + url sys.exit(1) if (response.status_code == 404): response = client.put(url, data = json.dumps(pool), headers = jsontype) if response.status_code == 201: # When creating a new resource we expect to get a 201 print 'Pool %s added' %(poolName) else: data = json.loads(response.content) print "Error adding pool %s: URL=%s Status=%d Id=%s: %s" %(poolName, url, response.status_code, data['error_id'], data['error_text']) else: if response.status_code == 200: print "Pool %s already exists" %(poolName) else: print "Error: Status=%d URL=%s" %(response.status_code, url) Running the example   This code was tested with Python 2.7.3 and version 1.1.0 of the requests library.   Run the Python script as follows:   $ addpool.py Pool pytest added   Notes   The only difference between doing a PUT to change a resource and a PUT to add a resource is the HTTP status code returned.  When changing a resource 200 is the expected status code and when adding a resource, 201 is the expected status code.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with Python - Overview    
View full article
The following code uses Stingray's RESTful API to a file to the extra directory.   The code is written in Python.  This program adds the file 'validserialnumbers' to the extra directory and if the file already exists it will be overwrite it.  If this is not the desired behavior, code can be added to to check for the existence of the file as was done in the addpool example.   addextrafile.py   #! /usr/bin/env python import requests import json import sys fileName = 'validserialnumbers' url = 'https://stingray.example.com:9070/api/tm/1.0/config/active/extra/' + fileName contentType = {'content-type': 'application/octet-stream'} validSerialNumbers = """\ 123456 234567 345678""" client = requests.Session() client.auth = ('admin', 'admin') client.verify = False try: response = client.put(url, data = validSerialNumbers, headers = contentType) except requests.exceptions.ConnectionError: print "Error: Unable to connect to " + url sys.exit(1) # If the file already exists, it will be replaced with this version and 204 will be returned # otherwise 201 will be returned. if response.status_code == 201 or response.status_code == 204: print "File %s added" %(fileName) else: error = json.loads(response.content) print "Error adding file %s: url=%s Status=%d Id=%s: %s" %(fileName, url, response.status_code, error['error_id'], error['error_text'])     Running the example   This code was tested with Python 2.7.3 and version 1.1.0 of the requests library.   Run the Python script as follows:   $ addextrafile.py File added   Notes   Since this is a file and not a configuration resource, JSON will not be used and the MIME type will be "application/octet-stream".  Another difference when dealing with files is how Stingray handles adding a file that already exists.  If the file already exists, Stingray will overwrite the it and return a HTTP status code of 204.  If the file doesn't already exist, the HTTP status code will be a 201.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with Python - Overview  
View full article
The following code uses Stingray's RESTful API to list all the pools defined on a cluster. The code is written in Python. This example has more extensive comments then the following examples and most of these are applicable to all the examples. This program does a single GET request for the list of pools and then loops through that list, each element of which is a dictionary, and then outputs the pool name.   listpools.py   #! /usr/bin/env python import requests # The REST Client import json # For serializing and deserializing JSON import sys print "Pools:\n" url = 'https://stingray.example.com:9070/api/tm/1.0/config/active/pools'; # Setup the session client = requests.Session() # Set the Userid and Password. These need to match a UserId and Password for a Stingray user client.auth = ('admin', 'admin') # Don't require that the Stingray's certiciate be from a certiticate authority because # Stingray certificates are self-signed. client.verify = False try: # Do the HTTP GET to get the lists of pools response = client.get(url) except requests.exceptions.ConnectionError: # We weren't able to connect to the Stingray. The most likely reasons for this are that the # hostname of the Stingray instance is incorrect, or this client doesn't have network access # to the Stingray instance or to port 9070 on the Stingray instance, or the RESTful API could # be disabled on the Stingray instance, or the Stingray instance isn't using the default port. print "Error: Unable to connect to " + url sys.exit(1) data = json.loads(response.content) # Deserialize the JSON response into a dictionary if response.status_code == 200: # We always expect a 200 # Since we are getting a list of pools we expect the first element to be 'children' if data.has_key('children'): # The value for the key 'children' will be a list containing a dictionary for each pool # with key, 'name', set to the name of the pool and key, 'href', set to the URL of the pool pools = data['children'] for i, pool in enumerate(pools): print pool['name'] # This is the name of the pool else: print 'Error: No children found' else: print "Error getting pool list: URL=%s Status=%d Id=%s: %s" %(url, response.status_code, data['error_id'], data['error_text'])   Running the example   This code was tested with Python 2.7.3 and version 1.1.0 of the requests library.   Run the Python script as follows:   $ listpools.py Pools:   Pool1 Pool2   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with Python - Overview  
View full article
The following code uses Stingray's RESTful API to enable or disabled a specific Virtual Server.   The code is written in PHP and uses STMRESTClient.  This program checks to see if the Virtual Server "test vs" is enabled and if it is, it disables it and if it is disabled, it enables it.  A GET is done to retrieve the configuration data for the Virtual Server and the "enabled" value in the "basic" properties section is checked.  This is a boolean value, so if it is true it is set to false and if it is false it is set to true. The changed data is then sent to the server using a PUT.   startstopvs.php   <?php # Start or stop a virtual server require_once 'stmrestclient.inc'; $resource = 'vservers/test vs'; print("<html><body>\n"); try { # Set up the connection $client = new STMRestClient(); # Get the config data for the virtual server $vsConfig = $client->get($resource); if ($vsConfig->properties->basic->enabled) { $vsConfig->properties->basic->enabled = false; print("test vs is enabled. Disable it<br>\n"); } else { $vsConfig->properties->basic->enabled = true; print("test vs is Diabled. Enable it<br>\n"); } $response = $client->put($resource, $vsConfig); } catch (STMConnectException $e) { print ("Error connecting to the REST API: " . $e->getMessage()); } catch (STMAuthException $e) { print ("Error logging into the REST API: " . $e->getMessage()); } catch (exception $e) { print ('Error: ' . $e->getMessage()); } print("</body></html>\n"); ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   test vs is enabled. Disable it.   or test vs is disabled. Enable it.     Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
This article discusses how to use the Stingray Traffic Manager's RESTful Control API with PHP.  The are different options for accessing the RESTful API with PHP, but I decided to create my own PHP REST Client, STMRESTClient, to make working with RESTful API easier, and this has been used in the PHP examples. Instructions for using STMRESTClient and the code can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   Resources   The RESTful API gives you access to the Stingray Configuration and statistics, presented in the form of resources.  The format of the data exchanged using the Stingray RESTful API will depend on the type of resource being accessed:   Data for Configuration ans Status Resources, such as Virtual Servers and Pools are exchanged in JSON format using the MIME type “application/json”, so when getting data for a resource with a GET request, the data will be returned in JSON format and must be deserialized or decoded into a PHP data structure.  When adding or changing a resource with a PUT request, the data must be serialized or encoded from a PHP data structure into JSON format.  Files, such as rules and those in the extra directory are exchanged in raw format using the MIME type “application/octet-stream”.   Working with JSON and PHP   PHP provides functions for JSON encoding and decoding. To take a PHP data structure and encode it into JSON format, use json_encode() and to decode a JSON formatted string into a PHP structure, use json_decode(). If using STMRestClient, JSON encoding and decoding will be done for you.   Working with the RESTful API and PHP   The base form of the URI for the Stingray RESTful API is:   https://<host>:<port>/api/tm/<version>   followed by paths to the different resource types:   For configuration resources: /config/active/ For statistic resources: /status/<host>/information/ "local_tm" can be used in place of <host> For information resources: /status/<host>/statistics/ "local_tm" can be used in place of <host>   followed by a actual resource, so for example to get a list of all the pools from the Stingray instance, stingray.example.com, it would be:   https://stingray.example.com:9070/api/tm/2.0/config/active/pools   and to get the configuration information for the pool, “testpool” it would be:   https://stingray.example.com:9070/api/tm/2.0/config/active/pools/testpool   and to get statistics for the pool "testpool", it would be:   https://stingray.example.com:9070/api/tm/2.0/status/local_tm/statistics/pools/testpool   Prerequisites   If your PHP environment does not have cURL installed, you will need to install it, even if you are using STMRestClient.   If using apt (assuming apache is the web server):   sudo apt-get install php5-curl sudo service apache2 restart   Data Structures   The PHP functions json_decode and json_encode convert between JSON strings and PHP data structures.  The PHP data structure can be either an associative array or an object.  In either case, the array or object will have one element.   The key to this element will be:   'children' for lists of configuration resources.  The value will be a PHP array with each element in the array being an associative array with the key, 'name', set to the name of the resource and the key, 'href', set to the URI of the resource. 'properties' for configuration resources.  The value will be an associative array with each key value pair being a section of properties with the key being set to the name of the section and the value being an associative array containing the configuration values as key/value pairs.  Configuration values can be scalars, arrays or associative arrays. 'statistics' for statistics resources.  The value will be an associative array. 'information' for information resources.  The value will be an associative array.   Please see Feature Brief: Traffic Manager's RESTful Control API for examples of these data structures and something like the Chrome REST Console can be used to see what the actual data looks like.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to list all the pools defined on a cluster. The code is written in PHP and uses STMRESTClient. This example has more extensive comments then the following examples and most of these are applicable to all the examples. This program does a single GET request for the list of pools and then loops through that list, each element of which is an associative array, and then outputs the pool name.   listpools.php   <?php # Display a list of pools require_once 'stmrestclient.inc'; print("<html><body>\n<br><b>Pools:</b><br><br>\n"); try { # Setup the connection to the REST API $client = new STMRestClient(); # Do the HTTP GET to get the lists of pools $response = $client->get('pools'); # Get the list of pools from the response as an object $pools = $response->children; # Loop through the list of pools foreach ($pools as $pool) { print($pool->name . "<br>\n"); } } catch (STMConnectException $e) { /* We weren't able to connect to the Stingray Traffic Manager REST API The most likely reasons for this are: - the hostname of the Stingray instance is incorrect - this client doesn't have network access to the Stingray instance or port 9070 - the RESTful API is disabled - the RESTful API is using using a different port */ print ("Error connecting to the REST API: " . $e->getMessage()); } catch (STMAuthException $e) { /* We were able to connect to the Stingray Traffic Manager REST API but could not log in The user name or password were incorrect. If they weren't specified then the default values are being used and may need to be changed or the user name and password can be specified */ print ("Error logging into the REST API: " . $e->getMessage()); } catch (exception $e) { print ('Error: ' . $e->getMessage()); } print("</body></html>\n"); ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   Pools: Pool1 Pool2   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to list all the pools defined for a cluster and for each pool it lists the nodes defined for that pool, including draining and disabled nodes. The code is written in PHP and uses STMRESTClient. This example builds on the previous listpools.php example.  This program does a GET request for the list of pool and then while looping through the list of pools, a GET is done for each pool to retrieve the configuration parameters for that pool.   listpoolnodes.php   <?php # Display a list of all nodes in all pools require_once 'stmrestclient.inc'; print("<html><body>\n<br><b>Pools:</b><br>\n"); try { $client = new STMRestClient(); $response = $client->get('pools'); $pools = $response->children; foreach ($pools as $pool) { $poolName = $pool->name; $poolConfig = $client->get("pools/$poolName"); $nodes = $poolConfig->properties->basic->nodes; $draining = $poolConfig->properties->basic->draining; $disabled = $poolConfig->properties->basic->disabled; print("<br>Pool: $poolName<br>\n"); print ' Nodes: '; foreach ($nodes as $node) { print "$node "; } print "\n"; if (count($draining)) { print ' Draining Nodes: '; foreach ($draining as $node) { print "$node "; } print "<br>\n"; } if (count($disabled)) { print ' Disabled Nodes: '; foreach ($disabled as $node) { print "$node "; } print "<br>\n"; } print "<br>\n"; } } catch (exception $e) { print ("Error: " . $e->getMessage()); } print("</body></html>\n"); ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   Pools:   Pool1     Nodes:  192.168.1.100 192.168.1.101     Draining:  192.168.1.101     Disabled:  192.168.1.102   Pool2     Nodes:  192.168.1.103 192.168.1.104   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to delete a pool.  The code is written in PHP and uses STMRESTClient.  This program deletes the "phptest" pool created by the addpool.php example.  To delete a resource you do a HTTP DELETE on the URI for the resource.  If the delete is successful a 204 HTTP status code will be returned.   deletepool.php   <?php # Delete a pool require_once 'stmrestclient.inc'; $poolName = 'phptest'; try { # Set up the connection $client = new STMRestClient(); /* Check to see if the pool exists. If it doesn't exist, then a * ResourceNotFoundException exception will be thrown. */ $response = $client->get("pools/$poolName"); $client->delete("pools/$poolName"); print("Pool $poolName deleted"); } catch (STMResourceNotFoundException $e) { # The pool doesn't exist print("Pool $poolName not found"); } catch (STMConnectException $e) { print ("Error connecting to the REST API: " . $e->getMessage()); } catch (STMAuthException $e) { print ("Error logging into the REST API: " . $e->getMessage()); } catch (Exception $e) { print ('Error: ' . $e->getMessage()); } print("</body></html>\n"); ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   Pool phptest deleted   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to add a pool.   The code is written in PHP and uses STMRESTClient. This program creates a new pool, "phptest", first doing a GET to make sure the pool doesn't already exist, and if the pool doesn't exist, the pool is created by doing a PUT with just the minimum data needed to create a pool.  In this case the program creates a properties object with just one node.  All other values will get default values when Stingray creates the pool.   addpool.php   <?php # Add a pool require_once 'stmrestclient.inc'; $poolName = 'phptest'; $node = '192.168.168.135:80'; try { # Set up the connection $client = new STMRestClient(); /* Check to see if the pool already exist. If it does not yet exist, then a * ResourceNotFoundException exception will be thrown. */ $response = $client->get("pools/$poolName"); print("Pool $poolName already exists"); } catch (STMResourceNotFoundException $e) { # The pool doesn't exist, so it can be created $poolConfig->properties->basic->nodes = array($node); #$poolConfig = array('properties' => array('basic' => array('nodes' => array($node)))); try { $response = $client->put("pools/$poolName", $poolConfig); print("Pool $poolName added"); } catch (Exception $e) { print ("Error creating Pool $poolName: " . $e->getMessage()); } } catch (STMConnectException $e) { print ("Error connecting to the REST API: " . $e->getMessage()); } catch (STMAuthException $e) { print ("Error logging into the REST API: " . $e->getMessage()); } catch (Exception $e) { print ('Error: ' . $e->getMessage()); } print("</body></html>\n"); ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   Pool phptest added   Notes   The only difference between doing a PUT to change a resource and a PUT to add a resource is the HTTP status code returned.  When changing a resource 200 is the expected status code and when adding a resource, 201 is the expected status code.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to a file to the extra directory.   The code is written in PHP and uses STMRESTClient.  This program adds the file 'validserialnumbers' to the extra directory and if the file already exists it will be overwrite it.  If this is not the desired behavior, code can be added to to check for the existence of the file as was done in the addpool example.   addextrafile.   <?php require_once 'stmrestclient.inc'; $fileName = 'validserialnumbers'; $validSerialNumbers = "123456\n234567\n345678\n"; try { # Set up the connection $client = new STMRestClient(); $client->put("extra/$fileName", $validSerialNumbers, 'application/octet-stream'); # If the file already exists, it will be replaced with this version and 204 will be returned # otherwise 201 will be returned. print("<br>statusCode=" . $client->statusCode . "<br><br>"); if ($client->statusCode == 201) { print("File $fileName added"); } else { print("File $fileName replaced"); } } catch (STMConnectException $e) { print ("Error connecting to the REST API: " . $e->getMessage()); } catch (STMAuthException $e) { print ("Error logging into the REST API: " . $e->getMessage()); } catch (exception $e) { print ("Error: " . $e->getMessage()); } ?>   Running the example   This code was tested with PHP 5.3.3 and uses the STMRestClient class that can be found here: Tech Tip: A Stingray Traffic Manager REST Client for PHP   To run this program, Make it available via a web server and the output should be:   File validserialnumbers added   or   File validserialnumbers replaced   Notes   Since this is a file and not a configuration resource, JSON will not be used and the MIME type will be "application/octet-stream".  Another difference when dealing with files is how Stingray handles adding a file that already exists.  If the file already exists, Stingray will overwrite the it and return a HTTP status code of 204.  If the file doesn't already exist, the HTTP status code will be a 201.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API Tech Tip: Using the RESTful Control API with PHP - Overview  
View full article
The following code uses Stingray's RESTful API to enable or disabled a specific Virtual Server.   The code is written in Perl.  This program checks to see if the Virtual Server "test vs" is enabled and if it is, it disables it and if it is disabled, it enables it.  A GET is done to retrieve the configuration data for the Virtual Server and the "enabled" value in the "basic" properties section is checked.  This is a boolean value, so if it is true it is set to false and if it is false it is set to true. The changed data is then sent to the server using a PUT.   startstopvs.pl   #!/usr/bin/perl use REST::Client; use MIME::Base64; use JSON; use URI::Escape; # Since Stingray is using a self-signed certificate we don't need to verify it $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; my $vs = "test vs"; # Because there is a space in the virtual serve name it must be escaped my $url = "/api/tm/1.0/config/active/vservers/" . uri_escape($vs); # Set up the connection my $client = REST::Client->new(); $client->setHost("https://stingray.example.com:9070"); $client->addHeader("Authorization", "Basic " . encode_base64("admin:admin")); # Get configuration data for the virtual server $client->GET($url); # Decode the json response. The result will be a hash my $vsConfig = decode_json $client->responseContent(); if ($client->responseCode() == 200) { if ($vsConfig->{properties}->{basic}->{enabled}) { # The virtual server is enabled, disable it. We only need to send the data that we # are changing so create a new hash with just this data. %newVSConfig = (properties => { basic => { enabled => JSON::false}}); print "$vs is Enabled. Disable it.\n"; } else { # The virtual server is disabled, enable it. %newVSConfig = (properties => { basic => { enabled => JSON::true}}); print "$vs is Diabled. Enable it.\n"; } $client->addHeader("Content-Type", "application/json"); $client->PUT($url, encode_json(\%newVSConfig)); $vsConfig = decode_json $client->responseContent(); if ($client->responseCode() != 200) { print "Error putting virtual server config. status=" . $client->responseCode() . " Id=" . $vsConfig->{error_id} . ": " . $vsConfig->{error_text} . "\n"; } } else { print "Error getting pool config. status=" . $client->responseCode() . " Id=" . $vsConfig->{error_id} . ": " . $vsConfig->{error_text} . "\n"; }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ startstopvs.pl test vs is enabled. Disable it.   Notes   This program it is sending only the 'enabled' value to the server by creating a new hash with just this value in the 'basic' properties section.  Alternatively, the entire Virtual Server configuration could have been returned to the server with just the enabled value changed.  Sending just the data that has changed reduces the chances of overwriting another user's changes if multiple programs are concurrently accessing the RESTful API.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API  
View full article
The following code uses Stingray's RESTful API to list all the pools defined for a cluster and for each pool it lists the nodes defined for that pool, including draining and disabled nodes. The code is written in Perl. This example builds on the previous listpools.pl example. This program does a GET request for the list of pool and then while looping through the list of pools, a GET is done for each pool to retrieve the configuration parameters for that pool.   listpoolnodes.pl   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 #!/usr/bin/perl     use REST::Client;   use MIME::Base64;   use JSON;     print "Pools:\n\n" ;     # Since Stingray is using a self-signed certificate we don't need to verify it   $ENV { 'PERL_LWP_SSL_VERIFY_HOSTNAME' } = 0;     my $url = "/api/tm/1.0/config/active/pools" ;   # Set up the connection   my $client = REST::Client->new();   $client ->setHost( "https://stingray.example.com:9070" );   $client ->addHeader( "Authorization" , "Basic " . encode_base64( "admin:admin" ));     # Request a list of pools   $client ->GET( $url );     # Decode the json response   my $response = decode_json( $client ->responseContent());   if ( $client ->responseCode() == 200) {        # Obtain a reference to the children array        my $poolArrayRef = $response ->{children};        foreach my $pool (@ $poolArrayRef ) {            my $poolName = $pool ->{name};            $client ->GET( "$url/$poolName" );            my $poolConfig = decode_json $client ->responseContent();            if ( $client ->responseCode() == 200) {                my $nodes = $poolConfig ->{properties}->{basic}->{nodes};                my $draining = $poolConfig ->{properties}->{basic}->{draining};                my $disabled = $poolConfig ->{properties}->{basic}->{disabled};                print "Pool: $poolName\n" ;                print "    Nodes: " ;                foreach my $node (@ $nodes ) {                    print "$node " ;                }                print "\n" ;                if ( scalar (@ $draining ) gt 0) {                    print "    Draining Nodes: " ;                    foreach my $node (@ $draining ) {                        print "$node " ;                    }                    print "\n" ;                }                if ( scalar (@ $disabled ) gt 0) {                    print "    Diabled Nodes: " ;                    foreach my $node (@ $disabled ) {                        print "$node " ;                    }                    print "\n" ;                }                print "\n" ;            } else {                print "Error getting pool config: status=" . $client ->responseCode() . " Id=" . $poolConfig ->{error_id} . ": " . $poolConfig ->{error_text} . "\n"            }        }   } else {        print "Error getting list of pools: status=" . $client ->responseCode() . " Id=" . $response ->{error_id} . ": " . $response ->{error_text} . "\n" ;   }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ listpoolnodes.pl Pools:   Pool1     Nodes:  192.168.1.100 192.168.1.101     Draining:  192.168.1.101     Disabled:  192.168.1.102   Pool2     Nodes:  192.168.1.103 192.168.1.104 >   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API  
View full article
The following code uses Stingray's RESTful API to list all the pools defined on a cluster. The code is written in Perl. This example has more extensive comments then the following examples and most of these are applicable to all the examples. This program does a single GET request for the list of pools and then loops through that list, each element of which is a hash, and then outputs the pool name.   listpools.pl   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 #!/usr/bin/perl     use REST::Client;   use MIME::Base64;   use JSON;     print "Pools:\n" ;     # Since Stingray is using a self-signed certificate we don't need to verify it   $ENV { 'PERL_LWP_SSL_VERIFY_HOSTNAME' } = 0;     # Set up the connection   my $client = REST::Client->new();   $client ->setHost( "https://stingray.example.com:9070" );   # Setup the basic authorization header with the encoded Userid and Password.   # These need to match a UserId and Password for a Stingray user   $client ->addHeader( "Authorization" , "Basic " . encode_base64( "admin:admin" ));     # Do the HTTP GET to get the lists of pools   $client ->GET( "/api/tm/1.0/config/active/pools" );     # Deserialize the JSON response into a hash   my $response = decode_json( $client ->responseContent());   if ( $client ->responseCode() == 200) {        # Obtain a reference to the children array        my $poolArrayRef = $response ->{children};        foreach my $pool (@ $poolArrayRef ) {            print $pool ->{name} . "\n" ;        }   } else {        # We weren't able to connect to the Stingray or there was a problem with the request.        # The most likely reasons for this are:        # - the hostname of the Stingray instance is incorrect        # - this client doesn't have network access to the Stingray instance or port 9070        # - the RESTful API is disabled        # - the RESTful API is using using a different port        # - the URL is incorrect        print "Error: status=" . $client ->responseCode() . " Id=" . $response ->{error_id} . ": " . $response ->{error_text} . "\n" ;   }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ listpoolnodes.pl Pools:   Pool11     Pool2       Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API  
View full article
The following code uses Stingray's RESTful API to delete a pool.  The code is written in Perl.  This program deletes the "pltest" pool created by the addpool.pl example.  To delete a resource you do a HTTP DELETE on the URI for the resource.  If the delete is successful a 204 HTTP status code will be returned.   deletepool.pl   #!/usr/bin/perl use REST::Client; use MIME::Base64; use JSON; # Since Stingray is using a self-signed certificate we don't need to verify it $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; my $poolName = 'pltest'; my $url = "/api/tm/1.0/config/active/pools/$poolName"; # Set up the connection my $client = REST::Client->new(); $client->setHost("https://stingray.example.com:9070"); $client->addHeader("Authorization", "Basic " . encode_base64("admin:admin")); #First see if the pool already exists $client->DELETE($url); if ($client->responseCode == 204) { print "Pool $poolName deleted"; } elsif ($client->responseCode == 404) { print "Pool $poolName not found"; } else { print "Error deleting pool $poolName. Status: " . $client->responseCode . " URL: $url"; }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ delelepool.pl Pool pltest deleted   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API  
View full article
The following code uses Stingray's RESTful API to add a pool.   The code is written in Perl. This program creates a new pool, "pltest", first doing a GET to make sure the pool doesn't already exist, and if the pool doesn't exist, the pool is created by doing a PUT with just the minimum data needed to create a pool.  In this case the program creates a properties hash with just one node.  All other values will get default values when Stingray creates the pool.   addpool.pl   #!/usr/bin/perl use REST::Client; use MIME::Base64; use JSON; # Since Stingray is using a self-signed certificate we don't need to verify it $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; my $poolName = 'pltest'; my %pool = (properties => {basic => {nodes => [ '192.168.168.135:80']}}); my $url = "/api/tm/1.0/config/active/pools/$poolName"; # Set up the connection my $client = REST::Client->new(); $client->setHost("https://stingray.example.com:9070"); $client->addHeader("Authorization", "Basic " . encode_base64("admin:admin")); #First see if the pool already exists $client->GET($url); if ($client->responseCode == 404) { $client->addHeader("Content-Type", "application/json"); $client->PUT($url, encode_json(\%pool)); my $poolConfig = decode_json $client->responseContent(); if ($client->responseCode() == 201) { # When creating a new resource we expect to get a 201 print "Pool $poolName added"; } else { print "Error adding pool. status=" . $client->responseCode() . " Id=" . $vsConfig->{error_id} . ": " . $vsConfig->{error_text} . "\n"; } } else { if ($client->responseCode() == 200) { print "Pool $poolName already exists"; } else { print "Error getting pool config. status=" . $client->responseCode() . " Id=" . $vsConfig->{error_id} . ": " . $vsConfig->{error_text} . "\n"; } }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ addpool.pl Pool pltest added   Notes   The only difference between doing a PUT to change a resource and a PUT to add a resource is the HTTP status code returned.  When changing a resource 200 is the expected status code and when adding a resource, 201 is the expected status code.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API  
View full article
The following code uses Stingray's RESTful API to a file to the extra directory.   The code is written in Perl.  This program adds the file 'validserialnumbers' to the extra directory and if the file already exists it will be overwrite it.  If this is not the desired behavior, code can be added to to check for the existence of the file as was done in the addpool example.   addextrafile.pl   #!/usr/bin/perl use REST::Client; use MIME::Base64; #Since Stingray is using a self-signed certificate we don't need to verify it $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; my $fileName = 'validserialnumbers'; my $url = "/api/tm/1.0/config/active/extra/$fileName"; my $validSerialNumbers = <<END; 123456 234567 345678 END # Set up the connection my $client = REST::Client->new(); $client->setHost("https://stingray.example.com:9070"); $client->addHeader("Authorization", "Basic " . encode_base64("admin:admin")); # For files, the MIME type is octet-stream $client->addHeader("Content-Type", "application/octet-stream"); $client->PUT($url, $validSerialNumbers); # If the file already exists, it will be replaced with this version and 204 will be returned # otherwise 201 will be returned. if ($client->responseCode() == 201 || $client->responseCode() == 204) { print "File $fileName added"; } else { print "Error adding file $fileName. Status: " . $client->responseCode() . " URL: $url"; }   Running the example   This code was tested with Perl 5.14.2 and version 249 of the REST::Client module.   Run the Perl script as follows:   $ addextrafile.pl File validserialnumbers added   Notes   Since this is a file and not a configuration resource, JSON will not be used and the MIME type will be "application/octet-stream".  Another difference when dealing with files is how Stingray handles adding a file that already exists.  If the file already exists, Stingray will overwrite the it and return a HTTP status code of 204.  If the file doesn't already exist, the HTTP status code will be a 201.   Read More   The REST API Guide in the   Product Documentation Feature Brief: Traffic Manager's RESTful Control API Collected Tech Tips: Using the RESTful Control API
View full article
Have you ever wanted to make use of LDAPs StartTLS functionality, or to restrict the search filters and attributes which external users can use when querying your directory service? How about simply rejecting or closing LDAP connections at will?   Although Stingray does not include a built-in LDAP protocol parser, you can use TrafficScript LDAP Library 1.1 to provide the TrafficScript functionality to decode and build up LDAP packets.  Then with a little TrafficScript logic, you can implement some sophisticated traffic management policies for LDAP traffic.   Example Uses     Restrict LDAP Operations   The script below will read in a packet from the client using getPacket(). The getPacket() function returns a hash containing the current request in a hash along with the protocolOp (Protocol Operation), Message ID (all LDAP packets have an ID), and some other data. Once we have the packet and we know what the protocolOp is we can decide what to do with it.   import libLdap.rts as ldap; $packet = ldap.getPacket(); $op = ldap.getOp($packet); $ip = request.getRemoteIP(); if( !string.ipmaskmatch( $ip,"10.0.0.0/8" )) { # Non LAN clients can only BIND, UNBIND, and SEARCH if( ( $op != “BindRequest” ) && ( $op != “SearchRequest” ) && ( $op != “UnbindRequest” )) { # Send back a Notice of Disconnection and close the socket ldap.close(); } }   In this case, we simply check if the client is on the LAN (in the 10.0.0.0/8 subnet), and if it is not, then we restrict the types of requests they can make to binding, searching, and unbinding from the server.   Please Note: It's important to remember to set LDAP TrafficScript rules you create to run on "every" request, not just "once" (unless you're only interested in the Bind of course).   Chose an LDAP server based on bindDN   Here's another scenario for you, this time we have multiple LDAP servers sitting on the network, and we want to direct users to a server based on their binding credentials. If the BindDN contains “dc=nbttech,dc=com” then we will use the nbttech ldap Servers. Alternatively if the BindDN contains “dc=riverbed,dc=com” then we will use the Riverbed ldap servers. Anonymous binds will be rejected.   import libLDAP.rts as ldap; $packet = ldap.getPacket(); $op = ldap.getOp( $packet ); if( $op == "BindRequest" ) { $details = ldap.getBindDetails( $packet ); if( $details["bindDN"] == “” ) { # Anonymous bind. I don't think so! ldap.rejectAnonBind( $packet["messageID"] ); } elseif( string.endswith( $details["bindDN"], “dc=nbttech,dc=com” )){ pool.use(“nbttech-ldap”); } elseif( string.endswith( $details["bindDN"], “dc=riverbed,dc=com” )){ pool.use(“riverbed-ldap”); } else { # Unknown bind domain. Log a warning and reject with invalid Credentials (49) log.warn( “UnknownBind:“. $details["bindDN"] ); ldap.rejectBind( $packet["messageID"], 49 ); } }   The getBindDetails() function also returns details of the authentication method (SIMPLE/SASL), the LDAP version, and the authentication data itself.   Override Attributes and filters   Another thing you may wish to do is to limit which attributes are sent out from the LDAP server, and possibly which parts of the LDAP tree are searchable. The libLdap library can be used to set attributes and filters on incoming requests to restrict which information the LDAP server returns.   In the TrafficScript below, we are going to override everything (mwah ha ha ha)....   First the script will detect the BindRequest and use connection.data.set() to store the bindDN in memory, If the bind is anonymous we will close the connection. If we then get a SearchRequest from the user we will retrieve the bindDN and limit the query base object to match the “dc” or “ou” used in the bind. We will also limit the attributes to “cn”, “uid”, and “gid”. Set the filter to match the bind users common name, and finally Set the search scope to a single level.   You are obviously unlikely to limit all of those things at once or all the time, but this sample script lets you see how they all work:   import libLDAP.rts as ldap; $packet = ldap.getPacket(); $op = ldap.getOp( $packet ); if( $op == "BindRequest" ){ $details = ldap.getBindDetails( $packet ); if( $details["bindDN"] == "") { ldap.rejectAnonBind( $packet["messageID"] ); } else { connection.data.set( "bindDN", $details["bindDN"] ); } } elseif ( $op == "SearchRequest" ) { $details = ldap.getSearchDetails( $packet ); $bindDN = connection.data.get( "bindDN" ); if( string.regexMatch( $bindDN, "(cn=.*?),(dc|ou=.*)" )) { # Set the Base object to be in the same domain as the binder $details[ "baseObject" ] = $2; # restrict the attributes returned to cn, uid and gid ldap.setSearchAttributes( $details, "cn uid gid" ); # Override the user supplied filter too. They can only search themselves. ldap.setSearchFilter( $details, "(". $1 .")" ); # Change the scope... why not ;-) $details[ "scope" ]=1; # Commit the changes request.set( ldap.updateSearch( $packet, $details )); }else{ # Oh dear failed to process search... Lets reject it ;-) ldap.rejectSearch( $packet["messageID"], "Failed to nobble search. So Denied. Sorry!" ); } }   StartTLS   At the time of writing, Stingray doesn't support StartTLS for LDAP out of the box, but with this TrafficScript you can implement it yourself quite simply. You will need to create two LDAP services, one plain ldap, and the other a ldaps service with SSL Offload enabled. Then you need a loop back pool to link the plain ldap service with the ldaps service.   Once you have that set up, you just need the script:   import libLDAP.rts as ldap; if( connection.data.get( "TLS" )) { # the connection is already in TLS mode, stop processing break; } $packet = ldap.getPacket(); $op = ldap.getOp( $packet ); if( $op == "ExtendedRequest" ) { if( ldap.isStartTLS( $packet )) { $ip = request.getRemoteIP(); # Only Accept StartTLS requests if the clients are not local if( !string.ipmaskmatch( $ip, "10.0.0.0/8" )) { # Set the TLS flag on the connection connection.data.set( "TLS", "yes" ); # Send the TSL acceptance packet ldap.acceptStartTLS( $packet ); # Use the ldaps loopback pool, and we're done :-) pool.use( "ldap-loop" ); } else { # LAN clients have TLS rejected and can carry on in clear text ldap.rejectStartTLS( $packet, "Use Plain Text please" ); } } }   The first thing this script does is check to see if a TLS flag has been set on the connection. If it exists then startTLS has already happened and we should exit, the packet is almost certainly encrypted. If the TLS flag is not set, we continue. The code checks for the startTLS command, and if the user is a remote user it sends back an accept, sets the TLS flag on the connection, and selects the loop back pool. Further LDAP processing can be performed in the LDAPS Virtual Server. If however we find the user is in the 10/8 subnet we reject the startTLS command and make them continue in plain text.   Use LDAP Simple Authentication for other Services   The libLDAPauth.rts library is a small library which uses libLDAP to verify user/passwords against an ldap server. At present it only does a simple BindRequest.  You may want to look at the built-in 'auth.query()' TrafficScript function now; that makes this legacy library somewhat redundant.   The simplest way to use is by using the checkLdapAuth() function. This function returns the LDAP result code, which should be 0 if the authentication was successful.   import libLDAPauth.rts as la; $auth = la.checkLdapAuth( "10.4.5.1", "389", "cn=user,dc=znbttech,dc=com", "password” ); if ( $auth == 0 ) { # success log.info( "UserAuthenticated" ); } else { # Failed log.warn( "User failed authentication:" . $auth); }
View full article
The libLDAP.rts library and supporting library files (written by Mark Boddington) allow you to interrogate and modify LDAP traffic from a TrafficScript rule, and to respond directly to an LDAP request when desired.   You can use the library to meet a range of use cases, as described in the document Managing LDAP traffic with libLDAP.rts.   Note: This library allows you to inspect and modify LDAP traffic as it is balanced by Stingray.  If you want to issue LDAP requests from Stingray, check out the auth.query() TrafficScript function for this purpose, or the equivalent Authenticating users with Active Directory and Stingray Java Extensions Java Extension.   Overview   A long, long time ago on a Traffic Manager far, far away, I (Mark Boddington) wrote some libraries for processing LDAP traffic in TrafficScript:   libBER.rts – This is a TrafficScript library which implements all of the required Basic Encoding Rules (BER) functionality for LDAP. It does not completely implement BER though, LDAP doesn't use all of the available types, and this library hasn't implemented those not required by LDAP. libLDAP.rts – This is a TrafficScript library of functions which can be used to inspect and manipulate LDAP requests and responses. It requires libBER.rts to encode the LDAP packets. libLDAPauth.rts – This is a small library which uses libLdap to provide simple LDAP authentication to other services.   That library (version 1.0) mostly focused on inspecting LDAP requests. It was not particularly well suited to processing LDAP responses. Now, thanks to a Stingray PoC being run in partnership with the guys over at Clever Consulting, I've had cause to revist this library and improve upon the original. I'm pleased to announce libLDAP.rts version 1.1 has arrived.     What's new in libLdap Version 1.1?   Lazy Decoding. The library now only decodes the envelope  when getPacket() or getNextPacket() is called. This gets you the MessageID and the Operation. If you want to process further, the other functions handle decoding additional data as needed. New support for processing streams of LDAP Responses. Unlike Requests LDAP Responses are typically made up of multiple LDAP messages. The library can now be used to process multiple packets in a response. New SearchResult processing functions: getSearchResultDetails(), getSearchResultAttributes() and updateSearchResultDetails()   Lazy Decoding   Now that the decoding is lazier it means you can almost entirely bypass decoding for packets which you have no interest in. So if you only want to check BindRequests and/or BindResponses then those are the only packets you need to fully decode. The rest are sent through un-inspected (well except for the envelope).   Support for LDAP Response streams   We now have several functions to allow you to process responses which are made up of multiple LDAP messages, such  as those for Search Requests. You can use a loop with the "getNextPacket($packet["lastByte"])" function to process each LDAP message as it is returned from the LDAP server. The LDAP packet hash  now has a "lastByte" entry to help you keep track of the messages in the stream. There is also a new skipPacket() function to allow you to skip the encoder for packets which ou aren't modifying.   Search Result Processing   With the ability to process response streams I have added a  number of functions specifically for processing SearchResults. The getSearchDetails() function will return a SearchResult hash which contains the ObjectName decoded. If you are then interested in the object you can  call getSearchResultAttributes() to decode the Attributes which have been returned. If you make any changes to the Search Result you can then call updateSearchResultDetails() to update the packet, and then encodePacket() to re-encode it. Of course if at any point you determine that no changes are needed then you can call skipPacket() instead.   Example - Search Result Processing   import libDLAP.rts as ldap; $packet = ldap.getNextPacket(0); while ( $packet ) { # Get the Operation $op = ldap.getOp($packet); # Are we a Search Request Entry? if ( $op == "SearchRequestEntry" ) { $searchResult = ldap.getSearchResultDetails($packet); # Is the LDAPDN within example.com? if ( string.endsWith($searchResult["objectName"], "dc=example,dc=com") ) { # We have a search result in the tree we're interested in. Get the Attributes ldap.getSearchResultAttributes($searchResult); # Process all User Objects if ( array.contains($searchResult["attributes"]["objectClass"], "inetOrgPerson") ) { # Log the DN and all of the attributes log.info("DN: " . $searchResult["objectName"] ); foreach ( $att in hash.keys($searchResult["attributes"]) ) { log.info($att . " = " . lang.dump($searchResult["attributes"][$att]) ); } # Add the users favourite colour $searchResult["attributes"]["Favourite_Colour"] = [ "Riverbed Orange" ]; # If the password attribute is included.... remove it hash.delete($searchResult["attributes"], "userPassword"); # Update the search result ldap.updateSearchResultDetails($packet, $searchResult); # Commit the changes $stream .= ldap.encodePacket( $packet ); $packet = ldap.getNextPacket($packet["lastByte"]); continue; } } } # Not an interesting packet. Skip and move on. $stream .= ldap.skipPacket( $packet ); $packet = ldap.getNextPacket($packet["lastByte"]); } response.set($stream); response.flush();   This example reads each packet in turn by calling getNextPacket() and passing the lastByte attribute from the previously processed packet as the argument. We're looking for SearchResultEntry operations, If we find one we pass the packet to getSearchResultDetails() to decode the object which the search was for in order to determine the DN. If it's in example.com then we decide to process further and decode the attributes with getSearchResultAttributes(). If the object has an objectClass of inetOrgPerson we then print the attributes to the event log, remove the userPassword if it exists and set a favourite colour for the user. Finally we encode the packet and move on to the next one. Packets which we aren't interested in modifying are skipped.   Of course, rather than do all this checking in the response, we could have checked the SearchRequest in a request rule and then used connection.data.set() to flag the message ID for further processing.   We should also have a request rule which ensures that the objectClass is in the list of attributes requested by the end-user. But I'll leave that as an exercise for the reader ;-)   If you want more examples of how this library can be used, then please check out the additional use cases here: Managing LDAP traffic with libLDAP.rts
View full article
An External Program Monitor for Traffic Manager that monitors the health of LDAP servers.   For instructions please see:  Tech Tip: High-availability LDAP LDAP Health Monitor   The attached ldap.zip file has an updated source.list file    
View full article
Using Stingray Traffic Manager to load balance a pool of LDAP servers for High Availability is a fairly simple process.  Here are the steps: Start up the Manage a new service wizard.  This is located in the top right corner of the Stingray Traffic Manager web interface, under the Wizards drop down. In step 2 of the wizard set the Protocol to LDAP.  The Port will automatically be set to 389, the default LDAP port.  Give the service a Name. In step 3 add in the hostnames or IP Addresses of each of your LDAP servers. At this point a virtual server and pool will be created.  Before it is usable a few additional changes may be made: Change the Load Balancing algorithm of the pool to Least Connections Create a new Session Persistence class of type IP-based persistence (Catalogs -> Persistence) and assign it to the Pool Create a Traffic IP Group (Services -> Traffic IP Groups) and assign it to the virtual server.  The Traffic IP Group is the IP Address LDAP clients will connect to. The final step is to install the LDAP Health Monitor.  The LDAP Health Monitor is an External Program Monitor that binds to the LDAP server, submits an LDAP query, and checks for a response.  Instructions to install the monitor are in the linked page.
View full article