cancel
Showing results for 
Search instead for 
Did you mean: 

Pulse Secure vADC

Sort by:
Why write a health monitor in TrafficScript?   The Health Monitoring capabilities (as described in Feature Brief: Health Monitoring in Traffic Manager) are very comprehensive, and the built-in templates allow you to conduct sophisticated custom dialogues, but sometimes you might wish to resort to a full programming language to implement the tests you need.   Particularly on the Traffic Manager Virtual Appliance, your options can be limited. There's a minimal Perl interpreter included (see Tech Tip: Running Perl code on the Traffic Manager Virtual Appliance), and you can upload compiled binaries (Writing a custom Health Monitor in C) and shell scripts. This article explains how you can use TrafficScript to implement health monitors, and of course with Java Extensions, TrafficScript can 'call out' to a range of third-party libraries as well.   Overview   We'll implement the solution using a custom 'script' health monitor.  This health monitor will probe a virtual server running on the local Traffic Manager (using an HTTP request), and pass it all of the parameters relevant to the health request.   A TrafficScript rule running on the Traffic Manager can perform the appropriate health check and respond with a 'PASS' (200 OK) or 'FAIL' (500 Error) response.   The health monitor script   The health monitor script is straightforward and should not need any customization.  It will take its input from the health monitor configuration.   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 #!/bin/sh  exec $ZEUSHOME /perl/miniperl -wx $0 ${1+ "[email protected]" }       if 0;       #!/usr/bin/perl  #line 7       BEGIN{          # Pull in the Traffic Manager libraries for HTTP requests          unshift @INC , "$ENV{ZEUSHOME}/zxtmadmin/lib/perl" , "$ENV{ZEUSHOME}/zxtm/lib/perl" ;  }       use Zeus::ZXTM::Monitor qw( ParseArguments MonitorWorked MonitorFailed Log );  use Zeus::HTMLUtils qw( make_query_string );  use Zeus::HTTP;       my %args = ParseArguments();       my $url = "http://localhost:$args{vsport}$args{path}?" .make_query_string( %args );  my $http = new Zeus::HTTP( GET => $url );  $http ->load();       Log ( "HTTP GET for $url returned status: " . $http ->code() );       if ( $http ->code() == 200 ) {      MonitorWorked();  } else {      MonitorFailed( "Monitor failed: " . $http ->code() . " " . $http ->body() );  }   Upload this to the Monitor Programs of the Extra Files section of the catalog, and then create an "External Program Monitor" based on that script.  You will need to add two more configuration parameters to this health monitor configuration:   vsport: This should be set to the port of the virutal server that will host the trafficscript test path: This is optional - you can use it if you want to run several different health tests from the trafficscript rule   Your configuration should look something like this:   The virtual server   Create an HTTP virtual server listening on the appropriate port number (vsport).  You can bind this virtual server to localhost if you want to prevent external clients from accessing it.   The virtual server should use the 'discard' pool - we're going to add a request rule that always sends a response, so there's no need for any backend nodes.   The TrafficScript Rule   The 'business end' of your TrafficScript health monitor resides in the TrafficScript rule.  This rule is invoked every time the health monitor script is run, and it is given the details of the node which is to be checked.   The rule should return a 200 OK HTTP response if the node is OK, and a different response (such as 500 Error) if the node has failed the test.   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 $path = http.getPath(); # Use 'path' if you would like to publish                           # several different tests from this rule       $ip = http.getFormParam( "ipaddr" );  $port = http.getFormParam( "port" );  $nodename = http.getFormParam( "node" );       # We're going to test the node $nodename on $ip:$port  #  # Useful functions include:  #   http.request.get/put/post/delete()  #   tcp.connect/read/write/close()  #   auth.query()  #   java.run()            sub Failed( $msg ) {      http.sendResponse( 500, "text/plain" , $msg , "" );  }       # Let's run a simple GET  $req = 'GET / HTTP/1.0  Host: www.riverbed.com       ';  $timeout = 1000; # ms  $sock = tcp. connect ( $ip , $port , $timeout );  tcp. write ( $sock , $req , $timeout );  $resp = tcp. read ( $sock , 102400, $timeout );       # Perform whatever tests we want on the response data.   # For example, it should begin with '200 OK'       if ( ! string.startsWith( $resp , "HTTP/1.1 200 OK" ) ) {      Failed( "Didn't get expected response status" );  }       # All good  http.sendResponse( 200, "text/plain" , "" , "" );  
View full article
Most of the data manipulation you'll do with TrafficScript will involve manipulating strings. Here is a quick account of the most useful string functions.   Strings are managed efficiently within the TrafficScript runtime engine, and memory copies are kept to a minimum.   Creating and concatenating strings   Assign a string to a variable:   1 $password = "Secret" ;   Many functions take strings as arguments, and return strings as values:   1 $host = http.getHeader( "Host" );    Concatenate strings with the '.' operator:   1 2 $greeting = "Hello, " . $name ;  $link = "<a href=\"" . $url . "\">Click here" ;<a>    Basic string functions   The length of a string:   1 $len = string.len( $mystring );   Skip or drop bytes off the start or end of a string:   1 2 3 4 5 $interpreter = "#!/bin/sh" ;  $str = string.skip( $interpreter , 2 ); # returns "/bin/sh"       $greeting = "Hello, world!..." ;  $msg = string.drop( $greeting , 4 ); # returns "Hello, world"    Remove whitespace from the start and end of a string:   1 2 $email = "  [email protected]  " ;  $email = string.trim( $email );  # returns "[email protected]"   The string.substring() function returns a substring from a string:   1 2 3 4 $time = "09:15:45" ;  $hr   = string.substring( $time , 0, 2 );  # returns "09"  $min = string.substring( $time , 3, 2 );  # returns "15"  $sec = string.substring( $time , 6, 2 );  # returns "45"    String tests   The following functions test the contents of a string:   1 2 3 4 5 6 7 8 9 10 11 12 if ( string.startsWith( $url , "http://" ) ) {      ... # $url begins "http://"  }       if ( string.endsWith( $url , ".php" ) ) {      ... # url ends ".php"  }       if ( string.contains( $url , "/.." ) ) {      ... # url contains "/.."  }    The string.find() function searches for a substring and returns its location:   1 2 3 4 $greeting = "Hello, world!" ;  $i = string.find( $greeting , "llo" );   # returns 2  $j = string.find( $greeting , "Hello" ); # returns 0  $k = string.find( $greeting , "name" );  # returns -1 (not found)    String compares can be performed with the '==', '!=', '<', '>', '<=' and '>=' operators:   1 2 3 if ( $protocol <= "1.0" ) {     ...  }   Note that TrafficScript's Type Casting Rules can affect the behaviour of a compare operation:   1 2 3 4 5 6 7 8 9 10 11 $count = "100" ;       # Do a string compare  if ( $protocol < "99" ) {      ...   }       # Do an integer compare  if ( $protocol < 99 ) {      ...  }   The string.cmp() and string.icmp() functions perform case sensistive and case insensitive string compares, returning negative, zero or positive values. Both arguments are converted to strings if necessary:   1 2 3 4 5 6 7 8 if ( string.cmp( $protocol , "1.0" ) < 0 ) {      ...  }       # This is identical  if ( string.icmp( $protocol , 1.0 ) < 0 ) {      ...  }   String matching and substitution   The string.wildmatch() function performs a shell-like wildcard match on a string. The character '?' matches any single character, and '*' matches any substring:   1 2 3 4 $url = http.getPath();  if ( string.wildmatch( $url , "/cgi-bin/*.cgi" ) ) {      ... # is a request for a CGI script, without pathinfo  }   Regular expression matching can be performed with the string.regexMatch() function. Stingray uses the standard PCRE regular expression syntax, and matches are placed in the magic $1 to $9 variables:   1 2 3 4 $id = "user=Joe, password=Secret" ;  if ( string.regexmatch( $id , "^user=(.*), password=(.*)$" ) ) {      log .info( "Got UserID: " . $1 . ", Password: " . $2 );  }    Perform case-insensitive regular expression matches using the optional third function argument:   1 string.regexmatch( $username , "joe" , "i" );   Regular expression substitutions are the easiest and most powerful way to perform complex string manipulation. Text in a string which matches the regular expression is replaced by the substitution:   1 2 # Rewrite requests for "/secure/something" to "/private/something"  $url = string.regexsub( $url , "^/secure" , "/private" );    Normally, only the first match is replaced; the optional "g" flag indicates that a 'global' replace should be performed, where every match is replaced.   1 2 3 4 5 # The document contains references to "oldsite.example.com";   # replace these with "newsite.enterprise.com"  $response = http.getResponseBody();  $response = string.regexsub( $response , "oldsite.example.com" , "newsite.example.com" , "g" );  http.setResponseBody( $response );    String encoding and decoding   Convert between case using string.toUpper() and string.toLower() :   1 2 3 $string = "AbCdEfG" ;  $upper = string.toUpper( $string ); # returns "ABCDEFG"  $lower = string.toLower( $string ); # returns "abcdefg"   HTML-encode a string for safe rendering in a browser using string.htmlEncode(); use string.htmlDecode() to reverse the operation:   1 2 3 4 5 $xss = " <script type= "mce-no/type" >// alert( 'Hello!' ); // </script> "; # This returns " <script>alert( 'Hello!' );</script>" $safe = string.htmlencode( $xss );   %-encode control characters, spaces and '%' in a string using string.escape(); use string.unescape() to reverse the operation:   1 2 # returns "Hello%20World!%0D%0A"  $str = string.escape( "Hello World!\r\n" );   You may want to manually replace incidences of "&", "?" and "=" with their %-encoded counterparts if you want to use the result in a URL.   Use Base64 encoding for a more universal encoding scheme: string.base64encode() and string.base64decode() encode and decode strings. Base64 is used for MIME-encoded messages, and in the HTTP Basic Authorization header.   1 2 3 # Encodes a username and password for HTTP BASIC authentication  $enc = string.base64encode( "user:passwd" );  http.setHeader( "Authorization" , "Basic " . $enc );   An alternative pair of functions would be string.hexEncode() and string.hexDecode() .   Finally, you can encrypt and decrypt strings using a passphrase and the AES cipher:   1 2 $encrypted = string.encrypt( $plaintext , $passphrase );  $plaintext = string.decrypt( $encrypted , $passphrase );    Read more: Collected Tech Tips: TrafficScript examples
View full article
Full Proxy load balancing   Traffic Manager functions as a proxy. It terminates TCP (and UDP) connections locally, and makes new connections to the target (back-end) servers. This is a consequence of the architecture of the software (user-level software running on a general-purpose kernel), and most modern traffic management devices use a similar architecture.   Previous-generation load balancers (aka layer 3-4 load balancers) are based on NAT-capable routers; their mode of operation is simply to make intelligent, load-based destination-NAT decisions on incoming traffic, rather than relying on a static routing table. The proxy mode of operation allows Traffic Manager to perform a range of network optimizations (including TCP offload and HTTP multiplexing) that is not possible with NAT-based L3/4 balancers. However, the proxy mode  is not 'transparent' to clients and servers in the fashion that at layer 3/4 load balancer would be:   Clients must be directed to connect to an IP address and port that the load balancer is listening on. This is generally achieved by mapping the DNS name of a service to a traffic IP address that the load balancer listens on, but some legacy or inflexible network architectures may not make this possible Servers will observe that the connections originate from the load balancer, not the remote client. This can be a problem if the server needs to perform logging or access control based on the client's IP address.   Transparent Proxy Load Balancing   It is possible to run Traffic Manager in a fashion that appears transparent to clients and servers, so it appears like a L3/4 proxy. There are two  independent steps to this:   Step 1. Transparent capturing of incoming connections   Put Traffic Manager inline in your network, i.e. as an intermediate gateway. Use iptables to capture selected packets that would otherwise be forwarded and raise them up to Traffic Manager:   # iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 80   This iptables rule intercepts all incoming TCP packets that are destined to port 80, any destination IP address, and rewrites the destination IP address to a local one (the primary IP address on the interface the packet was received on). It can optionally also rewrite the port (--to-port). The Linux kernel then makes a routing decision, observes that the packet is targeted for a local IP and passes it up to the application listening on the destination IP and port (i.e. Traffic Manager). You can manually enter the iptables rule from the Linux command line on the Traffic Manager system.   Step 2. Transparent forwarding of data   Because Traffic Manager acts as a proxy, it makes a new connection to the destination server. This connection will originate from an IP address on the Traffic Manager system; the back-end server will observe that the connection comes from Traffic Manager. This is not transparent.   The IP Transparency capability in a pool can spoof the source address of a connection to a back-end server - HowTo: Spoof source IP addresses with IP Transparency.  By default, it will set the source address to be the remote IP address of the client-side connection. From the back-end server’s perspective, the TCP or UDP packets it receives appear to originate from the remote client, so the Traffic Manager system is transparent.   This capability is enabled by the IP Transparency setting in the connection management properties of a pool:     There are two caveats to this technique:   It requires that the Traffic Manager box lies on the back-end server’s default route (typically, Traffic Manager is on the same local network so it is configured to be the default gateway for the server); It has a couple of performance impacts: Traffic Manager cannot use HTTP keepalive optimization, and the IP transparency module imposes a performance hit on the Traffic Manager kernel.   Nevertheless, it's a common deployment method when the traffic manager should appear transparent to the back-end servers.   Additional Notes   If you use the iptables technique to capture and rewrite incoming packets, the TrafficScript function request.getLocalIP() will return a local IP address.  You can use the function request.getDestIP() to determine the original destination IP address.   You can control how the IP address spoofing capability functions in two ways:   To avoid using IP transparency (for example, when managing protocols such as HTTP where transparency is often not necessary), select a pool that does not use IP transparency.  You can employ very fine-grained selection  - for example, only using IP Transparency for HTTP transactions where it is absolutely necessary   To explicitly control the source IP address, use the TrafficScript function request.setRemoteIP() as described in the article HowTo: Spoof source IP addresses with IP Transparency   This method does not enable you to use legacy layer 2/3 load balancing methods such as Techniques for Direct Server Return with Traffic Manager; Traffic Manager still functions as a full proxy, giving you the ability to apply the full suite of layer 7 optimizations and traffic manipulation that Traffic Manager makes available.
View full article
A document to hold useful regular expressions that I have pulled together for things: RegExr is a great and very handy online tool for checking regular expression matches: RegExr A regex to validate a password string to ensure it does not contain dangerous punctuation characters and is less than 20 characters long.  useful for Stingray Application Firewall form field protection in login pages: ^[^;,{}\[\]\$\%\*\(\)<>:?\\/'"`]{0,20}$ A regex to check that a password has at least one Uppercase, Lowercase, Numbers and Punctuation from the approved list and is at least 8 but less than 20 characters. ^(?=.*[A-Z])(?=.*[a-z])(?=.*[\\@^!\.,~-])(?=.*\d)(.{8,20})$ A regex to check a field has a valid email address in it ^[^@][email protected][^@]+ \. [^@]+ $
View full article
In a recent conversation, a user wished to use the Traffic Manager's rate shaping capability to throttle back the requests to one part of his web site that was particularly sensitive to high traffic volumes (think a CGI, JSP Servlet, or other type of dynamic application). This article describes how you might go about doing this, testing and implementing a suitable limit using Service Level Monitoring, Rate Shaping and some TrafficScript magic.   The problem   Imagine that part of your website is particularly sensitive to traffic load and is prone to overloading when a crowd of visitors arrives. Connections queue up, response time becomes unacceptable and it looks like your site has failed.   If your website were a tourist attraction or a club, you’d employ a gatekeeper to manage entry rates. As the attraction began to fill up, you’d employ a queue to limit entry, and if the queue got too long, you’d want to encourage new arrivals to leave and return later rather than to join the queue.   This is more-or-less the solution we can implement for a web site. In this worked example, we're going to single out a particular application (named search.cgi) that we want to control the traffic to, and let all other traffic (typically for static content, etc) through without any shaping.   The approach   We'll first measure the maximum rate at which the application can process transactions, and use this value to determine the rate limit we want to impose when the application begins to run slowly.   Using Traffic Manager's Service Level Monitoring classes, we'll monitor the performance (response time) of the search.cgi application. If the application begins to run slower than normal, we'll deploy a queuing policy that rate-limits new requests to the application. We'll monitor the queue and send a 'please try later' message when the rate limit is met, rather than admitting users to the queue and forcing them to wait.   Our goal is to maximize utilization (supporting as many transactions as possible), but minimise response time, returning a 'please wait' message rather than queueing a user.   Measuring performance   We first use zeusbench to determine the optimal performance that the application can achieve. We several runs, increasing the concurrency until the performance (responses-per-second) stabilizes at a consistent level:   zeusbench –c  5 –t 20 http://host/search.cgi zeusbench –c  10 –t 20 http://host/search.cgi zeusbench –c  20 –t 20 http://host/search.cgi   ... etc   Run:   zeusbench –c 20 –t 20 http://host/search.cgi     From this, we conclude that the maximum number of transactions-per-second that the application can comfortably sustain is 100.   We then use zeusbench to send transactions at that rate (100 / second) and verify that performance and response times are stable. Run:   zeusbench –r 100 –t 20 http://host/search.cgi     Our desired response time can be deduced to be approximately 20ms.   Now we perform the 'destructive' test, to elicit precisely the behaviour we want to avoid. Use zeusbench again to send requests to the application at higher than the sustainable transaction rate:   zeusbench –r 110 –t 20 http://host/search.cgi     Observe how the response time for the transactions steadily climbs as requests begin to be queued and the successful transaction rate falls steeply. Eventually when the response time falls past acceptable limits, transactions are timed out and the service appears to have failed.   This illustrates how sensitive a typical application can be to floods of traffic that overwhelm it, even for just a few seconds. The effects of the flood can last for tens of seconds afterwards as the connections complete or time out.   Defining the policy   We wish to implement the following policy:   If all transactions complete within 50 ms, do not attempt to shape traffic. If some transactions take more than 50 ms, assume that we are in danger of overload. Rate-limit traffic to 100 requests per second, and if requests exceed that rate limit, send back a '503 Too Busy' message rather then queuing them. Once transaction time comes down to less than 50ms, remove the rate limit.   Our goal is to repeat the previous zeusbench test, showing that the maximum transaction rate can be sustained within the desired response time, and any extra requests receive an error message quickly rather than being queued.   Implementing the policy   The Rate Class   Create a rate shaping class named Search limit with a limit of 100 requests per second.     The Service Level Monitoring class   Create a Service Level Monitoring class named Search timer with a target response time of 50 ms.     If desired, you can use the Activity monitor to chart the percentage of requests that confirm, i.e. complete within 50 ms while you conduct your zeusbench runs. You’ll notice a strong correlation between these figures and the increase in response time figures reported by zeusbench.   The TrafficScript rule   Now use these two classes with the following TrafficScript request rule:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # We're only concerned with requests for /search.cgi  $url = http.getPath();  if ( $url != "/search.cgi" ) break;       # Time this request using the Service Level Monitoring class  connection.setServiceLevelClass( "Search timer" );       # Test if any of the recent requests fell outside the desired SLM threshold  if ( slm.conforming( "Search timer" ) < 100 ) {      if ( rate.getBacklog( "Search limit" ) > 0 ) {         # To minimize response time, always send a 503 Too Busy response if the          # request exceeds the configured rate of 100/second.         # You could also use http.redirect() to a more pleasant 'sorry' page, but         # 503 errors are easier to monitor when testing with ZeusBench         http.sendResponse( "503 Too busy" ,  "text/html"           "<h1>We're too busy!!!</h1>" ,            "Pragma: no-cache" );      } else {         # Shape the traffic to 100/second         rate. use ( "Search limit" );      }  }     Testing the policy   Rerun the 'destructive' zeusbench run that produced the undesired behaviour previously:   Running:   zeusbench –r 110 –t 20 http://host/search.cgi     Observe that:   Traffic Manager processes all of the requests without excessive queuing; the response time stays within desired limits. Traffic Manager typically processes 110 requests per second. There are approximately 10 'Bad' responses per second (these are the 503 Too Busy responses generated by the rule), so we can deduce that the remaining 100 (approx) requests were served correctly.   These tests were conducted in a controlled environment, on an otherwise-idle machine that was not processing any other traffic. You could reasonably expect much more variation in performance in a real-world situation, and would be advised to set the rate class to a lower value than the experimentally-proven maximum.   In a real-world situation, you would probably choose to redirect a user to a 'sorry' page rather than returning a '503 Too Busy' error. However, because ZeusBench counts 4xx and 5xx responses as 'Bad', it is easy to determine how many requests complete successfully, and how many return the 'sorry' response.   For more information on using ZeusBench, take a look at the Introducing Zeusbench article.
View full article
Overview Traffic Manager's RESTful Control API allows HTTP clients to access and modify Traffic Manager cluster configuration data.  For example a program using standard HTTP methods can create or modify virtual servers and pools, or work with other Traffic Manager configuration objects.   The RESTful Control API can be used by any programming language and application environment that supports HTTP.   Resources   The Traffic Manager RESTful API is an HTTP based and published on port :9070.  Requests are made as standard HTTP requests, using the GET, PUT or DELETE methods.  Every RESTful call deals with a “resource”.  A resource can be one of the following:   A list of resources, for example, a list of Virtual Servers or Pools. A configuration resource, for example a specific Virtual Server or Pool. A file, for example a rule or a file from the extra directory.   Resources are referenced through a URI with a common directory structure.  For this first version of the Traffic Manager RESTful API the URI for all resources starts with “/api/tm/1.0/config/active”, so for example to get a list of pools, the URI would be “/api/tm/1.0/config/active/pools” and to reference the pool named “testpool”, the URI would be “/api/tm/1.0/config/active/pools/testpool.   When accessing the RESTful API from a remote machine, HTTPS must be used, but when accessing the RESTful API from a local Traffic Manager instance, HTTP can be used.   By default, the RESTful API is disabled and when enabled listens on port 9070.  The RESTful API can be enabled and the port can be changed in the Traffic Manager GUI by going to System->Security->REST API.   To complete the example, to reference the pool named “testpool” on the Traffic Manager instance with a host name of “stingray.example.com”, the full URI would be “https://stingray.example.com:9070/api/tm/1.0/config/active/pools/testpool”.  To get a list off all the types of resources available you can access the URL,  “https://stingray.example.com:9070/api/tm/1.0/config/active".   To retrieve the data for a resource you use the GET method, to add or change a resource you use the PUT method and to delete a resource you use the DELETE method.   Data Format   Data for resource lists and configuration resources are returned as JSON structures with a MIME type of "application/json".  JSON allows complex data structures to be represented as strings that can be easily passed in HTTP requests.  When the resource is a file, the data is passed in its raw format with a MIME type of "application/octet-stream".   For lists of resources the data returned will have the format:   { "children": [{ "name": "", "href": "/api/tm/1.0/config/active/pools/" }, { "name": "", "href": "/api/tm/1.0/config/active/pools/" }] }   For example, the list of pools, given two pools, “pool1” and “pool2” would be:   { "children": [{ "name": "pool1", "href": "/api/tm/1.0/config/active/pools/pool1" }, { "children": [{ "name": "pool2", "href": "/api/tm/1.0/config/active/pools/pool2" }] }   For configuration resources, the data will contain one or more sections of properties, always with at least one section named "basic", and the property values can be of different types.  The format looks like:   { "properties": { "<section name>": { "<property name>": "<string value>", "<property name>": <numeric value>, "<property name>": <boolean value>, "<property name>": [<value>, <value>], "<property name>": [<key>: <value>, <key>: <value>] }, "<section name>": { "<property name>": "<string value>", "<property name>": <numeric value>" } }   Accessing the RESTful API   Any client or program that can handle HTTP requests can be used to access the RESTful API. Basic authentication is used with the usernames and passwords matching those used to administer Traffic Manager.  To view the data returned by the RESTful API without having to do any programming, there are browser plug-ins that can be used.  One that is available, is the Chrome REST Console.  It is very helpful during testing to have something like this available.  One nice thing about a REST API is that it is discoverable, so using something like the Chrome REST Console, you can walk the resource tree and see everything that is available via the RESTful API.  You can also add, change and delete data.  For more information on using the Chrome REST Console see: Tech Tip: Using Traffic Manager's RESTful Control API with the Chrome REST Console   When adding or changing data, use the PUT method and for configuration resources, the data sent in the request must be in JSON format and must match the data format returned when doing a GET on the same type of resource.  For adding a configuration resource you do not need to include all properties, just the minimum sections and properties required to add the resource and this will vary for each resource.  When changing data you only need to include the sections and properties that need to be changed.  To delete a resource use the DELETE method.   Notes   An important caution when changing or deleting data is that this version of the RESTful API does do data integrity checking.  The RESTful API will allow you to makes changes that would not be allowed in the GUI or CLI.  For example, you can delete a Pool that is being used by a Virtual Server.  This means that when using the RESTful API, you should be sure to understand the data integrity requirements for the resources that you are changing or deleting and put validation in any programs you write. This release of the RESTful API is not compatible with Multi-Site Manager, so both cannot be enabled at the same time.   Read more   REST API Guide in the Product Documentation Collected Tech Tips: Using the RESTful Control API with Python Tech Tip: Using Stingray's RESTful Control API with the Chrome REST Console
View full article
The TrafficScript function http.changeSite() makes it easy to redirect clients from one domain to another.  You can also use it to reliably redirect clients from http to https (or https to http), or from one document tree on a website (e.g. /products) to another (e.g /sales). # Example: Redirect client from www.site.com to www.site.co.uk if( geo.getCountryCode( request.getRemoteIP() ) == "GB" ) {   http.changeSite( "www.site.co.uk" ); } # Example: Force client to https (assuming this rule is attached to an HTTP virtual server) http.changeSite( " https:// " . http.getHostHeader() ); # Example: move client from one tree to another $path = http.getPath(); if( string.startsWith( $path, "/products" ) ) http.changeSite( http.getHostHeader(). "/sales" ); For more fine-grained control of HTTP redirects, you can also use the http.redirect() function. Read more Collected Tech Tips: TrafficScript examples
View full article
TrafficScript is Traffic Manager's scripting and configuration language that lets you specify precisely how Traffic Manager must handle each type of request, in as much detail as you need. Without TrafficScript, you would have to configure your load balancer with a single, ‘lowest-common-denominator’ policy that describes how to handle all your network traffic. With TrafficScript, you control how Traffic Manager handles your traffic, inspecting and modifying each request and response as you wish, and pulling in each of Traffic Manager's features as you require.   What is TrafficScript?   TrafficScript is a high-level programming language used to create ‘rules’ which are invoked by the traffic manager each time a transaction request or response is received:   TrafficScript rules have full access to all request and response data, and give the you full control over how end users interact with the load balanced services.  They are commonly used to selectively enable particular Traffic Manager features (for example, bandwidth control, caching or security policies) and to modify request and response data to handle error cases or augment web page data.   Although TrafficScript is a new language, the syntax is intentionally familiar.  It is deeply integrated with the traffic management kernel for two reasons:   Performance: the integration allows for very efficient, high-performance interaction with the internal state of the traffic manager Abstraction: TrafficScript presents a very easy-to-use request/response event model that abstracts the internal complexities of managing network traffic away from the developer.   You can use TrafficScript to create a wide range of solutions and the familiar syntax means that complex code can be prototyped and deployed rapidly.   Example 1 - Modifying Requests   # Is this request a video download? $url = http.getPath(); if( string.wildmatch( $url, "/videos/*.flv" ) ) { # Rewrite the request to target an f4v container, not flv $url = string.replace( $url, ".flv", ".f4v" ); http.setPath( $url ); # We encode flash videos at 1088 Kbits max. Apply a limit to 2 Gbit # to control download tools and other greedy clients response.setBandwidthClass( "Videos 2Mbits" ); # We don't want to cache the response in the Stingray cache, even if # the HTTP headers state that it is cacheable http.cache.disable(); } A simple request rule that modifies the request and instructs the traffic manager to apply bandwidth and cache customizations   TrafficScript's close integration with the traffic management kernel makes it as easy to rewrite HTTP responses as HTTP requests:   Example 2 - Modifying Responses   $url = http.getResponseHeader( "Content-Type" ); if( !string.startsWith( $url, "text/html" ) ) break; $response = http.getResponseBody(); $response = string.replaceAll( $response, "http://intranet.mycorp.com/", "https://extranet.mycorp.com/" ); http.setResponseBody( $response ); A response rule that makes a simple replacement to change links embedded in HTTP responses   TrafficScript can invoke external systems in a synchronous or asynchronous fashion:   TrafficScript functions like http.request.get() , auth.query() and net.dns.resolveIP() will query an external HTTP, LDAP or DNS server and return the result of the query.  They operate synchronously (the rule is ‘blocked’ while the query is running) but the Traffic Manager will process other network traffic while the current rule is temporarily suspended. The TrafficScript function event.emit() raises an event to Stingray’s Event Handling system.  The TrafficScript rule continues to execute and the event is processed asynchronously. Events can trigger a variety of actions, ranging from syslog or email alerts to complex user-provided scripts.   These capabilities allow the Traffic Manager to interface with external systems to retrieve data, verify credentials or initiate external control-plane actions.   Example 3 - Accessing an external source (Google News)   $type = http.getResponseHeader( "Content-Type" ); if( $type != "text/html" ) break; # Stop processing this rule $res = http.request.get( "https://ajax.googleapis.com/ajax/services/search/news?". "v=1.0&q=Riverbed" ); $r = json.deserialize( $res ); $rs = $r['responseData']['results']; $html .= "<ul>\n"; foreach( $e in $rs ) { $html .= '<li>' . '<a href="'.$e['unescapedUrl'].'">'.$e['titleNoFormatting'].'</a>'. '</li>'; } $html .= "</ul>\n"; $body = http.getResponseBody(); $body = string.replace( $body, "<!--RESULTS-->", $html); http.setResponseBody( $body ); An advanced response rule that queries an external datasource and inserts additional data into the web page response   TrafficScript rules may also invoke Java Extensions.  Extensions may be written in any language that targets the JVM, such as Python or Ruby as well as Java. They allow developers to use third-party code libraries and to write sophisticated rules that maintain long-term state or perform complex calculations.   Getting started with RuleBuilder   The full TrafficScript language gives you access to over 200 functions, with the support of a proper programming language - variables, tests, loops and other flow control. You can write TrafficScript rules much as you'd write Perl scripts (or Python, JavaScript, Ruby, etc).   The RuleBuilder gives you a UI that lets you configure tests, and actions which are executed if one-of or all-of the tests are satisfied. The tests and actions you can use are predefined, and cover a subset of the full functions of TrafficScript. You can use the RuleBuilder much as you'd use the filtering rules in your email client.   RuleBuilder provides a simple way to create basic policies to control Traffic Manager   If you're not familiar with programming languages, then RuleBuilder is a great way to get started.  You can create simple policies to control Traffic Manager's operation, and then, with one click, transform them into the equivalent TrafficScript rule so that you can learn the syntax and extend them as required.  There's a good example to start with in the Stop hot-linking and bandwidth theft! article.   Examples   Collected Tech Tips: TrafficScript examples Top Examples of Traffic Manager in action (many solutions depend on TrafficScript)   Read More   TrafficScript Guide in the Product Documentation
View full article
This technical brief discusses Traffic Manager's Clustering and Fault Tolerance mechanisms ('TrafficCluster').   Clustering Traffic Managers are routinely deployed in clusters of two or more devices, for fault-tolerance and scalability reasons:     A cluster is a set of traffic managers that share the same basic configuration (for variations, see 'Multi-Site Management' below).  These traffic managers act as a single unit with respect to the web-based administration and monitoring interface: configuration updates are automatically propagated across the cluster, and diagnostics, logs and statistics are automatically gathered and merged by the admin interface.   Architecture - fully distributed, no 'master'   There is no explicit or implicit 'master' in a cluster - like the Knights of the Round Table, all Traffic Managers have equal status.  This design improves reliability of the cluster as there is no need to nominate and track the status of a single master device.   Administrators can use the admin interface on any Traffic Manager to manage the cluster.  Intra-cluster communication is secured using SSL and fingerprinting to protect against the interception of configuration updates or false impersonation (man-in-the-middle) of a cluster member.   Note: You can remove administration privileges from selected traffic managers by disabling the control!canupdate configuration setting for those traffic managers.  Once a traffic manager is restricted in that way, its peers will refuse to accept configuration updates from it, and the administration interface is disabled on that traffic manager.  If a restricted traffic manager is in some way compromised, it cannot be used to further compromise the other traffic managers in your cluster.   If you find yourself in the position that you cannot access any of the unrestricted traffic managers and you need to promote a restricted traffic manager to regain control, please refer to the technical note What to do if you need to access a restricted Traffic Manager.   Traffic Distribution across a Cluster Incoming network traffic is distributed across a cluster using a concept named 'Traffic IP Groups'.   A Traffic IP Group contains a set of floating (virtual) IP addresses (known as 'Traffic IPs') and it spans some or all of the traffic managers in a cluster: The Traffic Manager Cluster contains traffic managers 1, 2, 3 and 4.   Traffic IP Group A contains traffic IP addresses 'x' and 'y' and is managed by traffic managers 1, 2 and 3.   Traffic IP Group B contains traffic IP address 'z' and is managed by traffic managers 3 and 4. The traffic managers handle traffic that is destined to the traffic IP addresses using one of two methods:   Single-hosted traffic IP groups:  If a group is configured to operate in a 'single-hosted' fashion, each IP address is raised on a single traffic manager.  If there are multiple IP addresses in the group, the IP addresses will be shared between the traffic managers in an even fashion. Multi-hosted traffic IP groups:  If a group is configured to operate in a 'multi-hosted' fashion, each IP address is raised on all of the traffic managers.  The traffic managers publish the IP address using a multi-cast MAC address and employ the zcluster Kernel Modules for Linux Software module to filter the incoming traffic so that each connection is processed by one traffic manager, and the workload is shared evenly.   Single-hosted is typically easier to manage and debug in the event of problems because all of the traffic to a traffic IP address is targetted to the same traffic manager.  In high-traffic environments, it's common to assign multiple IP addresses to a single-hosted traffic IP group and let the traffic managers distribute those IP addresses evenly.  Publish all of the IP addresses in a round-robin DNS fashion.  This gives approximately even distribution of traffic across these IP addresses.   Multi-hosted traffic IP groups are more challenging to manage, but they have the advantage that all traffic is evenly distributed across the machines that manage the traffic IP group.   For more information, refer to the article Feature Brief: Deep-dive on Multi-Hosted IP addresses in Traffic Manager   If possible, you should use single-hosted traffic IP groups in very high traffic environments.  Although multi-hosted gives even traffic distribution, this comes at a cost:   Incoming packets are sprayed to all of the traffic managers in the multi-hosted traffic IP group, resulting in an increase in network traffic Each traffic manager must run the zcluster kernel module to filter incoming traffic; this module will increase the CPU utilization of the kernel on that traffic manager   Fault Tolerance   The traffic managers in a cluster each perform frequent self-tests, verifying network connectivity, correct operation and internal self-tests.  They broadcast health messages periodically (every 500 ms by default - see flipper!monitor_interval) and listen for the health messages from their peers.   If a traffic manager fails, it either broadcasts a health message indicating the problem, or (in the event of a catastrophic situation) it stops broadcasting health messages completely.  Either way, its peers in the Stingray cluster will rapidly identify that it has failed.   In this situation, two actions are taken:   An event is raised to notify the Event System that a failure has occured.  This will typically raise an alert in the event log and UI, and may send an email or other actions if they have been configured Any traffic IP addresses that the failed traffic manager was responsible for are redistributed appropriately across the remaining traffic managers in each traffic IP group   Note that if a traffic manager fails, it will voluntarily drop any traffic IP addresses that it is responsible for.   Failover   If a traffic manager fails, the traffic IP addresses that it is responsible for are redistributed.  The goal of the redistribution method is to share the  orphaned IP responsibilities as evenly as possible with the remaining traffic managers in the group, without reassigning any other IP allocations.  This minimizes disruption and seeks to ensure that traffic is as evenly shared as possible across the remaining cluster members.   The single-hosted method is granular to the level of individual traffic IP addresses.  The failover method is described in the article How are single-hosted traffic IP addresses distributed in a cluster (TODO).   The multi-hosted method is granular to the level of an individual TCP connection.  It's failover method is described in the article How are multihosted-hosted traffic IP addresses distributed in a cluster (TODO).   State sharing within a cluster   Stingray machines within a cluster will share some state information:   Configuration: Configuration is automatically replicated across the cluster and all traffic managers will hold an identical copy of the entire configuration at all points Health Broadcasts: Stingray machines periodically broadcast their health to the rest of the cluster Session Persistence data&colon; Some session persistence methods depend on Traffic Manager's internal store (see Session Persistence - implementing timeouts).  Local updates to that store are automatically replicated across the cluster on a sub-second granularity Bandwidth Data: Bandwidth classes that share a bandwidth allocation across a cluster (see Feature Brief: Bandwidth and Rate Shaping in Traffic Manager) will periodically exchange state so that each traffic manager can dynamically negotiate its share of the bandwidth class based on current demand   Traffic Manager does not share detailed connection information across a cluster (SSL state, rules state etc), so if a Traffic Manager were to fail, any TCP connections it is currently managing will be dropped.  You can guarantee that no connections are ever dropped by using a technique like VMware Fault Tolerance to run a shadow traffic manager that tracks the state of the active traffic manager completely.  This solution is supported and is in use in a number of deployments where 5- or 6-9's uptime is not sufficient: VMware Fault Tolerance is used to ensure that no connections are dropped in the event of a failure   Multi-Site Management   Recall that all of the traffic managers in a cluster have identical copies of configuration and therefore will operate in identical fashions.   Traffic Manager clusters may span multiple locations, and in some situations, you may need to run slightly different configurations in each location.  For example, you may wish to use a different pool of web servers when your service is running in your New York datacenter compared to your Docklands datacenter.   In simple situations, this can be achieved with judicious use of TrafficScript to apply slightly different traffic management actions based on the identity of the traffic manager that is processing the request ( sys.hostname() ), or the IP address that the request was received on: $ip = request.getLocalIP(); # Traffic IPs in the range 31.44.1.* are hosted in Docklands if( string.ipmaskMatch( $ip, "31.44.1.0/24" ) ) pool.select( "Docklands Webservers" ); # Traffic IPs in the range 154.76.87.* are hosted in New Jersey if( string.ipmaskMatch( $ip, "154.76.87.0/24" ) ) pool.select( "New Jersey Webservers" );   In more complex situations, you can enable the Multi-Site Management option for the configuration.  This option allows you to apply a layer of templating to your configuration - you define a set of locations, assign each traffic manager to one of these locations, and then you can template individual configuration keys so that they take different values depending on the location in which the configuration is read.   There are limitations to the scope of Multi-Site Manager (it currently does not interoperate with Web Application Firewall, and the REST API is not able to manage configuration that is templated using Multi-Site Manager).  Please refer to the What is Multi-Site Manager? feature brief for more information, and to the relevant chapter in the Product Documentation for details of limitations and caveats.   Read More   User Manual in the Product Documentation
View full article
Upgrading Traffic Manager Software The Traffic Manager user documentation contains a "Getting Started Guide" specific to each type of installation, including sections on upgrading to the latest version, depending on the platform type you are running on - refer to Installing and Upgrading your Pulse vADC for more information.   (this article has been updated to refer to a central location for Installation and Upgrades)  
View full article
  Traffic Manager does not provide a ‘connection mirroring’ or ‘transparent failover’ capability.  This article describes contemporary connection mirroring techniques and their strengths and limitations, and explains how Traffic Manager may be used with VMware Fault Tolerance to create an effective solution that preserves all connections in the event of a hardware failure, while processing them fully at layer 7. What is connection mirroring?   A fault tolerant load balancer cluster eliminates single points of failure:  When load balancers are deployed in a fault tolerant cluster, they present a reliable endpoint for the services they manage.  If one load balancer device fails, its peers are able to step in and accept traffic so the service can continue to operate.   …but a failover event will drop all established TCP connections: However, if a load balancer fails, any TCP connections that are established to that load balancer will be dropped.  Clients will either receive a RST or FIN close message, or they may just experience a timeout.  The clients will need to re-establish the TCP connection.  This is an inconvenience for long-lived protocols that do not support automatic reconnects, such as FTP.     Connection Mirroring offers a solution: If the load balancers are operating in a basic layer-4 packet forwarding mode, the only actions they perform is to NAT the packets to the correct target node, and to apply sequence number translation.  They can share this connection information with their peer.  If a load balancer fails, the TCP client will retransmit its packets after an appropriate timeout.  The packets will be received by the peer who can then apply the correct NAT and sequence number operations.   When is it appropriate to use connection mirroring?   Connection mirroring is best used when only very basic packet-based load balancing is in use.  For example, F5 recommend that you "enable connection mirroring on Performance (Layer 4) virtual servers only" and comment "mirroring short-term connections such as HTTP and UDP is not recommended, as this will cause a decrease in system performance... is typically not necessary, as those protocols allow for failure of individual requests without loss of the entire session".   Cisco also support layer 4 connection mirroring (referring to it as ‘Stateful Failover’) and note that it is only possible for layer 4 connections.  When using a Cisco ACE device, it is not possible to failover connections that are proxied, including connections that employ SSL decryption or HTTP compression.   Layer 7 connection mirroring imposes a significant network and CPU overhead   Layer 7 connection mirroring puts a very high load on the dedicated heartbeat link (all incoming packets are replicated to the standby peer) and is CPU intensive (both traffic managers must process the same transactions at layer 7). It may add latency or interfere with normal system operation, and not all ADC features are supported in a mirrored configuration.  Because of these limitations, F5 advise "the overhead incurred by mirroring HTTP connections is excessive given the minimal advantages."   Does connection mirroring guarantee seamless failover?   Due to timing and implementation details, connection mirroring does not guarantee seamless failover.  State data must be shared to the peer once the TCP connection is established, and this must be done asynchronously to avoid delaying every TCP connection.  If a load balancer fails before it has shared the state information, the TCP session cannot be resumed.   Typical duration of a TCP transaction (not including lingering keepalives) 500 ms Typical window before which state information is synchronized (implementation dependent) 200 ms (state exchanged 5 times per second) On failure, percentage of connections that cannot be re-established 200/500 = 40%   Connection mirroring does not guarantee seamless failover because connections must proceed while state is being shared   What is the effect of connection mirroring on uptime?   Connection mirroring carries a cost: increased internal traffic for state sharing, and severe limitations on the functionality that may be used at the load balancing tier.  What effect does it have on a service’s uptime?   Typical duration of a TCP transaction (not including lingering keepalives) 500 ms Typical number of individual load balancer failures in a 12 month period 5 Percentage of transactions that would be dropped if a load balancer failed 50% (assuming an active-active pair of load balancers)     Percentage of transactions that would be recovered on a failure 60% (analysis above: 40% would not be recovered)     What is the probability that an individual connection would be impacted by a load balancer failure? 500/(365.5*24*3600*1000) * 50% * 5 = 0.000000040 What is the probability that connection could be ‘rescued’ with connection mirroring? 60% = 0.6 What proportion of transactions would be impacted by a failure, and then recovered by connection mirroring? 0.000000040 * 0.6 = 0.000000024 (i.e. 0.0000024%)   Connection mirroring improves uptime by an infinitesimal amount   General advice   Consider using connection mirroring when: Operating in L2-4 NAT load balancing modes Performing NAT load balancing with no content inspection (no delayed binding) No content processing e.g. SSL, compression, caching, cookie injection is required Base protocol does not support automatic reconnects – e.g. FTP Connections are long-lived and a dropped connection would inconvenience the user, e.g. SSH Your load balancer is unreliable and failures are sufficiently frequent that the overhead of mirroring is worthwhile You are running a fault-tolerant pair of load balancers   Don’t use connection mirroring when: Operating in full proxy modes Performing NAT or full proxy load balancing with content inspection Compressing content, SSL decrypting, caching, session persistence methods that inject cookies, application firewall Base protocol supports reconnects – e.g. RDP Connections are short-lived and easily re-established e.g HTTP Your load balancers are reliable and you can accommodate instantaneous loss of connections in the event that one does fail You plan to run a cluster of three or more load balancers (this configuration is not supported by the major vendors who offer connection mirroring)   Benefits of using Connection Mirroring Improves uptime by 0.0000024% (typical) (2.4 millionths of a percent)   Costs of using Connection Mirroring Limits traffic inspection or manipulation in load balancer. Increases internal traffic and increases load on load balancer   Balance the benefits of connection limiting against the additional risk and complexity of enabling it and the potential loss in performance and functionality that will result.  Be aware that, based on the preceding analysis, unless your goal is to achieve more than 7-9’s uptime (99.99999%), connection mirroring will not measurably contribute to the reliability of your service.   When connections are too valuable to lose…   Pulse customers include emergency and first-response services around the world, NGO services publishing disaster-response information and even major political fund-raising concerns. In each case, extremely high availability and consistent performance in the face of large spikes of traffic are paramount to the organizations who selected Traffic Manager.   A number of customers use VMware Fault Tolerance with Traffic Manager to achieve enhanced uptime without compromising the any of the functionality that Traffic Manager offers. VMware Fault Tolerance maintains a perfect shadow of a running virtual machine, running on a separate host.  If the primary virtual machine fails due to a catastrophic hardware failure, the shadow seamlessly takes over all traffic, including established connections, with a typical latency of less than 1 ms. All application-level workloads, such as SSL decryption, TrafficScript processing and Authentication are maintained without any interruption in service:   VMware Fault Tolerance runs a secondary virtual machine in ‘lock step’ with the primary. Network traffic and other non-determinstic events are replicated to the secondary, ensuring that it maintains an identical execution state to the primary. If the primary fails, the secondary takes over seamlessly and a new secondary is started.   Such configurations leverage standard VMware technology and are fully supported. They have been proven in production and offer enhanced connection mirroring functionality compared to proprietary ADC solutions
View full article
Dynamic information is more abundant now than ever, but we still see web applications provide static content. Unfortunately many websites are still using a static picture for a location map because of application code changes required. Traffic Manager provides the ability to insert the required code into your site with no changes to the application. This simplifies the ability to provide users dynamic and interactive content tailored for them.  Fortunately, Google provides an API to use embedded Google maps for your application. These maps can be implemented with little code changes and support many applications. This document will focus on using the Traffic Manager to provide embedded Google Maps without configuration or code changes to the application.   "The Google Maps Embed API uses a simple HTTP request to return a dynamic, interactive map. The map can be easily embedded in your web page by setting the Embed API URL as the src attribute of an iframe...   Google Maps Embed API maps are easy to add to your webpage—just set the URL you build as the value of an iframe's src attribute. Control the size of the map with the iframe's height and width attributes. No JavaScript required. "... -- Google Maps Embed API — Google Developers   Google Maps Embedded API Notes   Please reference the Google Documentation at Google Maps Embed API — Google Developers for additional information and options not covered in this document.   Google API Key   Before you get started with the Traffic Script, your need to get a Google API Key. Requests to the Google Embed API must include a free API key as the value of the URL key parameter. Your key enables you to monitor your application's Maps API usage, and ensures that Google can contact you about your website/application if necessary. Visit Google Maps Embed API — Google Developers to for directions to obtain an API key.   By default, a key can be used on any site. We strongly recommend that you restrict the use of your key to domains that you administer, to prevent use on unauthorized sites. You can specify which domains are allowed to use your API key by clicking the Edit allowed referrers... link for your key. -- Google Maps Embed API — Google Developers   The API key is included in clear text to the client ( search nerdydata for "https://www.google.com/maps/embed/v1/place?key=" ). I also recommend you restrict use of your key to your domains.   Map Modes   Google provides four map modes available for use,and the mode is specified in the request URL.   Place mode displays a map pin at a particular place or address, such as a landmark, business, geographic feature, or town. Directions mode displays the path between two or more specified points on the map, as well as the distance and travel time. Search mode displays results for a search across the visible map region. It's recommended that a location for the search be defined, either by including a location in the search term (record+stores+in+Seattle) or by including a center and zoom parameter to bound the search. View mode returns a map with no markers or directions.   A few use cases:   Display a map of a specific location with labels using place mode (Covered in this document). Display Parking and Transit information for a location with Search Mode.(Covered in this document). Provide directions (between locations or from the airport to a location) using Directions mode Display nearby Hotels or tourist information with Search mode using keywords or "lodging" or "landmarks" Use geo location and Traffic Script and provide a dynamic Search map of Gym's local to each visitor for your fitness blog. My personal favorite for Intranets Save time figuring out where to eat lunch around the office and use Search Mode with keyword "restaurant" Improve my Traffic Script productivity and use Search Mode with keyword "coffee+shops"   Traffic Script Examples   Example 1: Place Map (Replace a string)   This example covers a basic method to replace a string in the HTML code. This rule will replace a string within the existing HTML with Google Place map iframe HTML, and has been formatted for easy customization and readability.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #Only process text/html content  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;        $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;   $googleapikey = "YOUR_KEY_HERE" ;   $googlemapurl = "https://www.google.com/maps/embed/v1/place" ;   #Map height and width   $mapheight = "420" ;   $mapwidth = "420" ;        #String of HTML to be replaced   $insertstring = "<!-- TAB 2 Content (Office Locations) -->" ;        #Replacement HTML   $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .   "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=" .   "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .        #Get the existing HTTP Body for modification   $body = http.getResponseBody();        #Regex sub against the body looking for the defined string   $body = string.replaceall( $body , $insertstring , $googlemaphtml );   http.setResponseBody( $body );    Example 2: Search Map (Replace a string) This example is the same as Example 1, but a change in the map type (note the change in the $googlemapurl?q=parking+near). This rule will replace a string within the existing HTML with Google Search map iframe HTML, and has been formatted for easy customization and readability.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #Only process text/html content  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;           $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;    $googleapikey = "YOUR_KEY_HERE" ;    $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;    #Map height and width    $mapheight = "420" ;    $mapwidth = "420" ;           #String of HTML to be replaced    $insertstring = "<!-- TAB 2 Content (Office Locations) -->" ;           #Replacement HTML    $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .    "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" .    "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .           #Get the existing HTTP Body for modification    $body = http.getResponseBody();           #Regex sub against the body looking for the defined string    $body = string.replaceall( $body , $insertstring , $googlemaphtml );    http.setResponseBody( $body );    Example 3: Search Map (Replace a section)   This example provides a different method to insert code into the existing HTML. This rule uses regex to replace a section of the existing HTML with Google map iframe HTML, and has also been formatted for easy customization and readability. The change from Example 2 can be noted (See $insertstring and string.regexsub).   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 #Only process text/html content       if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;           $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;    $googleapikey = "YOUR_KEY_HERE" ;    $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;    #Map height and width    $mapheight = "420" ;    $mapwidth = "420" ;          #String of HTML to be replaced    $insertstring = "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ;          #Replacement HTML    $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .    "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" .    "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .          #Get the existing HTTP Body for modification    $body = http.getResponseBody();          #Regex sub against the body looking for the defined string    $body = string.regexsub( $body , $insertstring , $googlemaphtml );    http.setResponseBody( $body );     Example 3.1 (Shortened)   For reference a shortened version of the Example 3 Rule above (with line breaks for readability):   1 2 3 4 5 6 7 8 if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;                http.setResponseBody ( string.regexsub( http.getResponseBody(),      "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ,      "<iframe width=\"420\" height=\"420\" frameborder=\"0\" style=\"border:0\" " .      "src=\"https://www.google.com/maps/embed/v1/search?" .      "q=parking+near+680+Folsom+St.+San+Francisco,+CA+94107" .      "&key=YOUR_KEY_HERE\"></iframe>" ) );     Example 4: Search Map ( Replace a section with formatting, select URL, & additional map)   This example is closer to a production use case. Specifically this was created with www.riverbed.com as my pool nodes. This rule has the following changes from Example 3: use HTML formatting to visually integrate with an existing application (<div class=\"six columns\">), only process for the desired URL path of contact (line #3), and provides an additional Transit Stop map (lines 27-31).   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 #Only process text/html content in the contact path  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" )       || http.getpath() == "contact" ) break;       $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;  $mapcenter = string.urlencode( "37.784465,-122.398570" );  $mapzoom = "14" ;  #Google API key  $googleapikey = "YOUR_KEY_HERE" ;  $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;  #Map height and width  $mapheight = "420" ;  $mapwidth = "420" ;       #Regex match for the HTML section to be replaced  $insertstring = "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ;       #Replacment HTML  $googlemapshtml =   #HTML cleanup (2x "</div>") and New Section title  "</div></div></a><h4>Parking and Transit Information</h4>" .  #BEGIN Parking Map. Using existing css for layout  "<div class=\"six columns\"><h5>Parking Map</h5>" .  "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" frameborder=\"0\" " .  "style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" . $nearaddress . "" .  "&key=" . $googleapikey . "\"></iframe></div>" .  #BEGIN Transit Map. Using existing css for layout  "<div class=\"six columns\"><h5>Transit Stop's</h5>" .  "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" frameborder=\"0\" " .  "style=\"border:0\" src=\"" . $googlemapurl . "?q=Transit+Stop+near+" . $nearaddress . "" .  "&center=" . $mapcenter . "&zoom=" . $mapzoom . "&key=" . $googleapikey . "\"></iframe></div>" .  #Include the removed HTML comment  "<!-- TAB 2 Content (Office Locations) -->" ;       #Get the existing HTTP Body for modification  $body = http.getResponseBody();       #Regex sub against the body looking for the defined string  $body = string.regexsub( $body , $insertstring , $googlemapshtml );  http.setResponseBody( $body );    Example 4.1 (Shortened)   For reference a shortened version of the Example 4 Rule above (with line breaks for readability):   1 2 3 4 5 6 7 8 9 10 11 12 13 14 if ( !string.startsWith ( http.getResponseHeader( "Content-Type" ), "text/html" )         || http.getpath() == "contact" ) break;           http.setResponseBody( string.regexsub(  http.getResponseBody() ,    "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ,     "</div></div></a><h4>Parking and Transit Information</h4><div class=\"six columns\">" .    "<h5>Parking Map</h5><iframe width=\"420\" height=\"420\" frameborder=\"0\" " .    "style=\"border:0\" src=\"https://www.google.com/maps/embed/v1/search" .    "?q=parking+near+680+Folsom+St.+San+Francisco,+CA+94107&key=YOU_KEY_HERE\"></iframe>" .  "</div><div class=\"six columns\"><h5>Transit Stop's</h5><iframe width=\"420\" " .  "height=\"420\" frameborder=\"0\" style=\"border:0\" " .  "src=\"https://www.google.com/maps/embed/v1/search?q=Transit+Stop+near+" .  "680+Folsom+St.+San+Francisco,+CA+94107&center=37.784465%2C-122.398570&zoom=14" .  "&key=YOUR_KEY_HERE\"></iframe></div><!-- TAB 2 Content (Office Locations) -->" ) );  
View full article
Important note - this article illustrates an example of authenticating traffic using Java Extensions.  Stingray TrafficScript also includes LDAP/Active Directory primitives, in the form of auth.query() , and these are generally simpler and easier to use than a Java-based solution.   Overview   A very common requirement for intranet and extranet applications is the need to authenticate users against an Active Directory (or LDAP) database. The Java Extension in this article describes how to do exactly that.   This article describes two Java Extensions that manage the HTTP Basic Authentication process and validate the supplied username and password against an Active Directory database. It shows how to use Initialization Parameters to provide configuration to an extension, and how authentication results can be cached to reduce the load on the Active Directory server.   A basic Java Extension   The first Java Extension verifies that the supplied username and password can bind directly to the LDAP database.  It's appropriate for simple LDAP deployments, but enterprise AD deployments may not give end users permissions to bind directly to the entire database, so the second example may be more appropriate.   The Java Extension (version 1)   import java.io.IOException; import java.io.PrintWriter; import java.util.Hashtable; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zeus.ZXTMServlet.ZXTMHttpServletRequest; public class LdapAuthenticate extends HttpServlet { private static final long serialVersionUID = 1L; private String dirServer; private String realm; public void init( ServletConfig config) throws ServletException { super.init( config ); dirServer = config.getInitParameter( "DB" ); realm = config.getInitParameter( "Realm" ); if( dirServer == null ) throw new ServletException( "No DB configured" ); if( realm == null ) realm = "Secure site"; } public void doGet( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { try { ZXTMHttpServletRequest zreq = (ZXTMHttpServletRequest)req; String[] userPass = zreq.getRemoteUserAndPassword(); if( userPass == null ) throw new Exception( "No Authentication details" ); Hashtable<String, String> env = new Hashtable<String, String>(); env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put( Context.PROVIDER_URL, "LDAP://" + dirServer ); env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" ); env.put( Context.SECURITY_PRINCIPAL, userPass[0] ); env.put( Context.SECURITY_CREDENTIALS, userPass[1] ); DirContext ctx = new InitialDirContext( env ); ctx.close(); // No exceptions thrown... must have been successful ;-) return; } catch( Exception e ) { res.setHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"" ); res.setHeader( "Content-Type", "text/html" ); res.setStatus( 401 ); String message = "<html>" + "<head><title>Unauthorized</title></head>" + "<body>" + "<h2>Unauthorized - please log in</h2>" + "<p>Please log in with your system username and password</p>" + "<p>Error: " + e.toString() + "</p>" + "</body>" + "</html>"; PrintWriter out = res.getWriter(); out.println( message ); } } public void doPost( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { doGet( req, res ); } }     Configuring the Java Extension   Upload the LdapAuthenticate Java Extension into the Java Catalog page. Click on the LdapAuthenticate link to edit the properties of the extension, and add two Initialization Parameters:   DB specifies the name of the LDAP or Active Directory database, and Realm specifies the authentication realm.   These parameters are read when the extension is initialized, which occurs the first time the extension is used by Stingray:   public void init( ServletConfig config) throws ServletException { super.init( config ); dirServer = config.getInitParameter( "DB" ); realm = config.getInitParameter( "Realm" ); if( dirServer == null ) throw new ServletException( "No DB configured" ); if( realm == null ) realm = "Secure site"; }   If you change the value of one of these parameters, use the 'Force Reload' option in the Stingray Admin Server to unload and reload this extension.   Either use the auto-generated rule, or create a new TrafficScript rule to call the extension on every request to an HTTP virtual server:   java.run( "LdapAuthenticate" );   Testing the Java Extension   When you try to access the web site through Stingray, you will be prompted for a username and password; the LdapAuthenticate extension checks that the username and password can bind to the configured Active Directory database, and refuses access if not: If you are unable to log in, cancel the prompt dialog box to see the error reported by the Java extension. In the following case, there was a networking problem; the extension could not contact the database server provided in the 'DB' parameter: Caching the Authentication Results   Caching the Authentication response from the Java extension will improve the performance of the web site and reduce the load on the database server.   You can modify the TrafficScript rule that calls the extension so that it records successful logins, caching them for a period of time. The following rule uses the data.set() TrafficScript function to record successful logins, caching this information for 10 minutes before attempting to reauthenticate the user against the database server.   $auth = http.getHeader( "Authorization" ); if( data.get( $auth ) < sys.time() ) { data.remove( $auth ); java.run( "LdapAuthenticate" ); # if we got here, we were authenticated. # Cache this information for 600 seconds data.set( $auth, sys.time()+600 ); }   A more sophisticated Java Extension implementation   In enterprise deployments, users often cannot bind to the LDAP or Active Directory database directly.  This example runs a custom search against the Active Directory database to locate the distinguishedName corresponding to the userid provided in the login attempt, then attempts to verify that the user can bind using their distinguishedName and the password they provided.   The Java Extension (version 2)   import java.io.IOException; import java.io.PrintWriter; import java.util.Hashtable; import javax.naming.NamingEnumeration; import javax.naming.Context; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zeus.ZXTMServlet.ZXTMHttpServletRequest; public class LdapAuthenticate extends HttpServlet { private static final long serialVersionUID = 1L; private String dirServer; private String realm; private String authentication; private String bindDN; private String bindPassword; private String baseDN; private String filter; public void init( ServletConfig config) throws ServletException { super.init( config ); dirServer = config.getInitParameter( "DB" ); if( dirServer == null ) throw new ServletException( "No DB configured" ); realm = config.getInitParameter( "Realm" ); if( realm == null ) realm = "Secure site"; authentication = config.getInitParameter( "authentication" ); if( authentication == null ) authentication = "simple"; bindDN = config.getInitParameter( "bindDN" ); if( dirServer == null ) throw new ServletException( "No bindDN configured" ); bindPassword = config.getInitParameter( "bindPassword" ); if( dirServer == null ) throw new ServletException( "No bindPassword configured" ); baseDN = config.getInitParameter( "baseDN" ); if( dirServer == null ) throw new ServletException( "No baseDN configured" ); filter = config.getInitParameter( "filter" ); if( dirServer == null ) throw new ServletException( "No filter configured" ); } public void doGet( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { try { ZXTMHttpServletRequest zreq = (ZXTMHttpServletRequest)req; String[] userPass = zreq.getRemoteUserAndPassword(); if( userPass == null ) throw new Exception( "No Authentication details" ); Hashtable<String, String> env = new Hashtable<String, String>(); env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put( Context.PROVIDER_URL, "LDAP://" + dirServer ); env.put( Context.SECURITY_AUTHENTICATION, authentication ); /* Bind with admin credentials */ NamingEnumeration<SearchResult> ne; String searchfilter = filter.replace( "%u", userPass[0] ); try { env.put( Context.SECURITY_PRINCIPAL, bindDN ); env.put( Context.SECURITY_CREDENTIALS, bindPassword ); DirContext ctx = new InitialDirContext( env ); String[] attrIDs = { "distinguishedName" }; SearchControls sc = new SearchControls(); sc.setReturningAttributes( attrIDs ); sc.setSearchScope(SearchControls.SUBTREE_SCOPE); ne = ctx.search(baseDN, searchfilter, sc); ctx.close(); } catch( Exception e ) { throw new Exception( "Failed to bind with master credentials: " + e.toString() ); } if( ne == null || !ne.hasMore() ) { throw new Exception( "No such user " + userPass[0] ); } SearchResult sr = (SearchResult) ne.next(); Attributes attrs = sr.getAttributes(); Attribute dnAttr = attrs.get("distinguishedName"); String dn = (String) dnAttr.get(); /* Now bind using dn with the user credentials */ try { env.put( Context.SECURITY_PRINCIPAL, dn ); env.put( Context.SECURITY_CREDENTIALS, userPass[1] ); DirContext ctx = new InitialDirContext( env ); ctx.close(); } catch( Exception e ) { throw new Exception( "Failed to bind with user credentials: " + e.toString() ); } // No exceptions thrown... must have been successful ;-) return; } catch( Exception e ) { res.setHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"" ); res.setHeader( "Content-Type", "text/html" ); res.setStatus( 401 ); String message = "<html>" + "<head><title>Unauthorized</title></head>" + "<body>" + "<h2>Unauthorized - please log in</h2>" + "<p>Please log in with your system username and password</p>" + "<p>Error: " + e.toString() + "</p>" + "</body>" + "</html>"; PrintWriter out = res.getWriter(); out.println( message ); } } public void doPost( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException { doGet( req, res ); } }   This version of the Java Extension takes additional initialization parameters: It first searches the database for a distinguishedName using a query resembling:   $ ldapsearch -h DB -D bindDN -w bindPassword -b baseDN filter distinguishedName   Where the %u in the filter is replaced with the username in the login attempt.   It then attempts to bind to the database using a query resembling:   $ ldapsearch -h DB -D distinguishedName -w userpassword   ... and permits access if that bind is successful.
View full article
Following up on this earlier article try using the below TrafficScript code snippet to automatically insert the Google Analytics code on all your webpages.  To use it:   Copy the rule onto your Traffic Manager  by first navigating Catalogs -> Rules Scroll down to Create new rule, give the rule a name, and select Use TrafficScript Language.  Click Create Rule to create the rule. Copy and paste the rule below. Change $account to your Google Analytics account number. If you are using multiple domains as described here set $multiple_domains to TRUE and set $tld to your Top Level Domain as specified in your Google Analytics account. Set the rule as a Response Rule in your Virtual Server by navigating to Services -> Virtual Servers -> <your virtual server> -> Rules -> Response Rules and Add rule.   After that you should be good to go.  No need to individually modify your web pages, TrafficScript will take care of it all.   # # Replace UA-XXXXXXXX-X with your Google Analytics Account Number # $account = 'UA-XXXXXXXX-X'; # # If you are tracking multiple domains, ie yourdomain.com, # yourdomain.net, etc. then set $mutliple_domains to TRUE and # replace yourdomain.com with your Top Level Domain as specified # in your Google Analytics account # $multiple_domains = FALSE; $tld = 'yourdomain.com'; # # Only modify text/html pages # if( !string.startsWith( http.getResponseHeader( "Content-Type" ), "text/html" )) break; # # This variable contains the code to be inserted in the web page. Do not modify. # $html = "\n<script type=\"text/javascript\"> \n \ var _gaq = _gaq || []; \n \ _gaq.push(['_setAccount', " . $account . "]); \n"; if( $multiple_domains == TRUE ) { $html .= " _gaq.push(['_setDomainName', " . $tld . "]); \n \ _gaq.push(['_setAllowLinker', true]); \n"; } $html .= " _gaq.push(['_trackPageview']); \n \ (function() { \n \ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; \n \ ga.src=('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; \n \ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); \n \ })(); \n \ </script>\n"; # # Insert the code right before the </head> tag in the page # $body = http.getResponseBody(); $body = string.replace( $body, "</head>", $html . "</head>"); http.setResponseBody( $body );
View full article
We have created dedicated installation and configuration guides for each type of deployment option, as part of the complete documentation set for Pulse vTM.
View full article
'Server First', 'Client First' and 'Generic Streaming' protocols are the most basic L7 protocol types that Traffic Manager can use to manage traffic. They are useful when managing custom protocols or simple TCP connections because they do not expect the traffic to conform to any specific format. This document describes the difference between Server First, Client First and Generic Streaming protocols, and explains some of the details of managing them.     Server-first protocols Server-first is the simplest. When Traffic Manager receives a connection from a client, it immediately runs any TrafficScript rules, then immediately connects to a back-end server. It then listens on both connections (client-side and server-side) and passes data from one side to the other as it comes.   Load-balancing a simple server-first protocol, such as TIME or MySQL   Server-first protocols may be one-shot protocols such as Time (where the server writes the response data, then immediately closes the connection), or complex protocols like MySQL (where the server opens the dialog with a password challenge).   Client-first Protocols   Client-first is an optimization of server-first. On the client-side, Traffic Manager is only alerted when a connection has been established and data has been received. Traffic Manager then proceeds in the style of server-first, i.e. runs TrafficScript rules, connects to back-end and relays data back and forth. In practice, you can use server-first any time you use client-first, but client-first is more efficient when a client is expected to write the first data.   Load-balancing a client-first protocol such as HTTP   When you use a client-first procotol, you can use TrafficScript rules to inspect the client's request data before making your load-balancing decision.   Server-first with 'server banner'   Server-first with a 'server banner' is a different optimization (to cater for servers which broadcast a banner on connect, such as SMTP). When a client connects, Traffic Manager immediately writes the configured 'server-first banner' to the client, then proceeds as a regular client-first connection. In addition, Traffic Manager slurps and discards the first line or data (terminated by a \n) that the server sends.   Load-balancing a simple server-first protocol with a greeting banner, such as SMTP or FTP   Once again, you can use TrafficScript rules to inspect the client's request data before making your load-balancing decision.   Generic Streaming   Generic Streaming is a very basic connection handing mode that does not allow for any synchronization.  It's best suited for long-lived asynchronous protocols where either party may initiate a transaction, such as WebSockets or chat protocols.   Load-balancing an unsynchronized protocol such as chat or websockets   If the protocol has a well-defined handshake (such as WebSockets) you can attach rules to manage the handshake.  You can create rules that manage the subsequent, asynchronous packets but you should take care not to call TrafficScript functions that would block (such as request.read() ) as these will stall data flowing in the other direction in the connection.   Troubleshooting Protocol problems   Timeouts   All connections have associated timeouts on connect and data. If a connect does not complete within the 'connect' timeout, or the connection is idle for the 'idle timeout', the connection will be discarded.   If it's a server-side connection, it will count as a server failure; three successive failures mark the node as dead.   The timeouts and 'three-failures' count can all be tuned if necessary via the Connection Management settings in the Virtual Server and Pool, and the Global Settings page.   Deadlocks   A request or response rule can cause the connection to block. For example, if Traffic Manager runs a request rule that calls 'request.read()', the connection will block until the required data has been read from the client. During this period, Traffic Manager stops relaying data from the server.   This may stall a connection or even trigger a timeout; be very careful if you use read (or write) TrafficScript functions with a bi-directional protocol.   Examples   The generic protocols typically function 'out-of-the-box' - all of the other protocols implemented by Traffic Manager layer on top of these and add protocol-specific handlers and optimizations.   Inspecting and managing generic protocols is challenging.  The following articles describe such advanced use of these protocols:   Virtual Hosting FTP services Managing WebSockets traffic with Traffic Manager Building a load-balancing MySQL proxy with TrafficScript
View full article
Update: 2013 06018 - I had to do 50 conversions today, so I have attached a shell script to to automate this process. == Assumptions: You have a pkcs12 bundle with a private key and certificate in it - in this example we will use a file called www.website.com.p12.  I use SimpleAuthority as it is cross platform and the free edition lets you create up to 5 keypairs, which is plenty for the lab... You don't have a password on the private key (passwords on machine loaded keys are a waste of time IMHO) You have a Linux / MacOS X / Unix system with openssl installed (Mac OS X does by default, so do most Linux installs...) 3 commands you need: First we take the p12 and export just the private key (-nocerts) and export it in RSA format with no encryption (-nodes) openssl pkcs12 -in www.website.com.p12 -nocerts -out www.website.com.key.pem -nodes Second we take the p12 and export just the certificate (-nokeys) and export it in RSA format with no encryption (-nodes) openssl pkcs12 -in www.website.com.p12 -nokeys -out www.website.com.cert.pem -nodes Third, we convert the private key into the format Stingray wants it in (-text) openssl rsa -in www.website.com.key.pem -out www.website.com.key.txt.pem -text You are left with a list of files, only two of them are needed to import into the Stingray: www.website.com.key.txt.pem is the private key you need www.website.com.cert.pem is the certificate you need These can then be imported into the STM under Catalogues > SSL > Server Certs Hope this helps.. 1 ~ $ ./p12_convert.sh -h ./p12_convert.sh written by Aidan Clarke <aidan.clarke at riverbed.com> Copyright Riverbed Technologies 2013 usage: ./p12_convert.sh -i inputfile -o outputfile This script converts a p12 bundle to PEM formated key and certificate ready for import into Stingray Traffif Manager OPTIONS:    -h      Show this message    -i      Input file name    -o      Output file name stub
View full article
Installation   Unzip the download ( Stingray Traffic Manager Cacti Templates.zip ) Via the Cacti UI, “Import Templates” and import the Data, Host, and Graph templates.  * Included graph templates are not required for functionality. Copy the files for the Cacti folder in the zip file to their corresponding directory inn your cacti install. Stingray Global Values script query - /cacti/site/scripts/stingray_globals.pl Stingray Virtual Server Table snmp query - cacti/resource/snmp_queries/stingray_vservers. Assign the host template to Traffic Manager(s) and create new graphs.   * Due to the method used by Cacti for creating graphs and the related RRD files, it is my recommendation NOT to create all graphs via the Device Page.   If you create all the graphs via the “*Create Graphs for this Host” link on the device page, Cacti will create an individual data source (RRD file and SNMP query for each graph) resulting in a significant amount of wasted Cacti and Device resources. Test yourself with the Stingray SNMP graph.   My recommendation is to create a single initial graph for each Data Query or Data Input method (i.e. one for Virtual Servers and one for Global values) and add any additional graphs via the Cacti’s Graph Management using the existing Data Source Drop downs.   Data Queries   Stingray Global Values script query - /cacti/site/scripts/stingray_globals.pl * Perl script to query the STM for most of the sys.globals values Stingray Virtual Server Table snmp query - cacti/resource/snmp_queries/stingray_vservers.xml * Cacti XML snmp query for the Virtual Servers Table MIB   Graph Templates   Stingray_-_global_-_cpu.xml Stingray_-_global_-_dns_lookups.xml Stingray_-_global_-_dns_traffic.xml Stingray_-_global_-_memory.xml Stingray_-_global_-_snmp.xml Stingray_-_global_-_ssl_-_client_cert.xml Stingray_-_global_-_ssl_-_decryption_cipher.xml Stingray_-_global_-_ssl_-_handshakes.xml Stingray_-_global_-_ssl_-_session_id.xml Stingray_-_global_-_ssl_-_throughput.xml Stingray_-_global_-_swap_memory.xml Stingray_-_global_-_system_-_misc.xml Stingray_-_global_-_traffic_-_misc.xml Stingray_-_global_-_traffic_-_tcp.xml Stingray_-_global_-_traffic_-_throughput.xml Stingray_-_global_-_traffic_script_data_usage.xml Stingray_-_virtual_server_-_total_timeouts.xml Stingray_-_virtual_server_-_connections.xml Stingray_-_virtual_server_-_timeouts.xml Stingray_-_virtual_server_-_traffic.xml     Sample Graphs (click image for full size)           Compatibility   This template has been tested with STM 9.4 and Cacti 0.8.8.a   Known Issues   Cacti will create unnecessary queries and data files if the “*Create Graphs for this Host” link on the device page is used. See install notes for work around.   Conclusion   Cacti is sufficient with providing SNMP based RRD graphs, but is limited in Information available, Analytics, Correlation, Scale, Stability and Support.   This is not just a shameless plug; Brocade offers a MUCH more robust set of monitoring and performance tools.
View full article
When managing the Traffic Manager Virtual Appliance you might need to free some space to perform certain tasks. This is usually most visible when performing upgrades where you might be presented with the following message: Analyzing system: failed  ERROR: Not enough space available, need 300000KB, however only xxxxxxKB is available   You can perform the following steps:   If you've previously uploaded a zeus upgrade package (.zpkg file) for a major upgrade, this can now be safely removed. Remove unnecessary files left over from a previous upgrade: (remove /opt/zeus/.upgrade and /opt/zeus.extract.* ) Remove any cached charts from the activity graphs: /opt/zeus/zxtmadmin/docroot/cache/ * If you've uploaded anything to /root that isn't needed any more, delete those files. Remove old versions of the traffic manager software as described below. Back up some old log files and remove them from /logs. Remove any temporary files from the /logs partition: /logs/.tmp/* Extend the logs partition as described in the Product Documentation - Virtual Appliance Getting Started Guide   Generally, the /logs partition has more free space than the /root partition.  You should move the upgrade package (.zpkg) and other temporary files to that partition rather than root.   If all else fails, you can generate a disk space report that lists the largest folders and files on each partition as follows:   # du -ax / | sort -rn | head -50 # du -ax /logs | sort -rn | head -50   Provide this information to Riverbed Technical Support.   Removing Previous Software Versions   When you upgrade the Virtual Appliance, the previous version of the software is retained so that you can revert back to it at any point in time. If you upgrade through a series of minor revisions you might have several older versions of the software still installed. In practice, it is unlikely that you need to retain all of these; having a single version that is known to be good should suffice.   Use the following command to list the software versions that are installed in the currently running partition:   # /opt/zeus/zxtm/bin/rollback --delete   You can safely delete old software versions using this interactive command if you are certain that you will not need to roll-back to them at some point in the future.   Web Application Firewall   In a manner similar to the Traffic Manager itself, the previous versions of the Web Application Firewall are retained following an upgrade. As with the Traffic Manager you can remove these old software versions to free disk space if you are certain that you will no longer need to roll-back to them.   Version 4.5 or later of the Web Application Firewall provides an interface to manage installed versions, the interface can be accessed via the Traffic Manager administration interface.   Application Firewall > Administration > Cluster Management > Updater > Open Update Center   After logging into the Update Center, use the "Undeploy" action to remove any inactive versions you no longer require.
View full article
Feature Brief: Pulse Traffic Manager RESTful Control API is one of the 'Control Plane' APIs provided by Pulse Traffic Manager (see also Feature Brief: Pulse Traffic Manager SOAP API). This article contains a selection of simple technical tips and solutions that use the REST Control API to manage and query Pulse Traffic Manager.   Overview Tech Tip: Using the RESTful Control API with Python Tech Tip: Using the RESTful Control API with Perl Tech Tip: Using the RESTful Control API with Ruby Tech Tip: Using the RESTful Control API with TrafficScript Tech Tip: Using the RESTful Control API with PHP   Example programs   Retrieving resource configuration data Tech Tip: Using the RESTful Control API with Python - listpools Tech Tip: Using the RESTful Control API with Perl - listpools Tech Tip: Using the RESTful Control API with Ruby - listpools Tech Tip: Using the RESTful Control API with TrafficScript - listpools Tech Tip: Using the RESTful Control API with PHP - listpools Tech Tip: Using the RESTful Control API with Python - listpoolnodes Tech Tip: Using the RESTful Control API with Perl - listpoolnodes Tech Tip: Using the RESTful Control API with Ruby - listpoolnodes Tech Tip: Using the RESTful Control API with TrafficScript - listpoolnodes Tech Tip: Using the RESTful Control API with PHP - listpoolnodes   Changing resource configuration data Tech Tip: Using the RESTful Control API with Python - startstopvs Tech Tip: Using the RESTful Control API with Perl - startstopvs Tech Tip: Using the RESTful Control API with Ruby - startstopvs Tech Tip: Using the RESTful Control API with TrafficScript - startstopvs Tech Tip: Using the RESTful Control API with PHP - startstopvs Adding a resource Tech Tip: Using the RESTful Control API with Python - addpool Tech Tip: Using the RESTful Control API with Perl - addpool Tech Tip: Using the RESTful Control API with Ruby - addpool Tech Tip: Using the RESTful Control API with TrafficScript - addpool Tech Tip: Using the RESTful Control API with PHP - addpool Tech Tip: Creating a new service with the REST API and Python   Deleting a resource Tech Tip: Using the RESTful Control API with Python - deletepool Tech Tip: Using the RESTful Control API with Perl - deletepool Tech Tip: Using the RESTful Control API with Ruby - deletepool Tech Tip: Using the RESTful Control API with TrafficScript - deletepool Tech Tip: Using the RESTful Control API with PHP - deletepool   Adding a file Tech Tip: Using the RESTful Control API with Python - addextrafile Tech Tip: Using the RESTful Control API with Perl - addextrafile Tech Tip: Using the RESTful Control API with Ruby - addextrafile Tech Tip: Using the RESTful Control API with PHP - addextrafile   Other Examples HowTo: List all of the draining nodes in Traffic Manager using Python and REST HowTo: Drain a node in multiple pools (Python REST API example) Deploying Python code to Pulse Traffic Manager Slowing down busy users - driving the REST API from TrafficScript Tech Tip: Using the RESTful Control API to get pool statistics with PHP Read More   The REST API Guide in the Product Documentation Feature Brief: Pulse Traffic Manager RESTful Control API
View full article