A question came up on an internal mailing list regarding getting the configuration off of the LTM into a format that can be parsed by an external tool.  In this case, the request was for an XML format of the BIG-IP configuration.  With iControl, It’s fairly simple to query configuration objects and it’s just a matter of throwing in a few print statements to build a XML document of the object hierarchy.

This article will show you how to query the list of LTM virtual servers and their child properties and objects and then export the values into XML.

Initialization

I’ve implemented this sample in Perl, but it just as easily could have been written in any language you prefer.  The benefit of perl is that it can be run from the command prompt on the BIG-IP itself.

the script starts with the normal perl declaration and variable assignments.  The input parameters are validated and then the SOAP specific typecasting is specified to tell the SOAP parser about the native iControl enumeration types.

   1: #!/usr/bin/perl
   2: use SOAP::Lite;
   3:  
   4: my $BIGIP = $ARGV[0];
   5: my $User = $ARGV[1];
   6: my $Pass = $ARGV[2];
   7:  
   8: sub usage()
   9: {
  10:   die ("Usage: LtmConfigToXml.pl host uid pwd\n");
  11: }
  12:  
  13: if ( ($BIGIP eq "") or ($User eq "") or ($Pass eq "") )
  14: {
  15:   usage();
  16: }
  17:  
  18: #----------------------------------------------------------------------------
  19: # Transport Information
  20: #----------------------------------------------------------------------------
  21: sub SOAP::Transport::HTTP::Client::get_basic_credentials
  22: {
  23:   return "$User" => "$Pass";
  24: }
  25:  
  26: $urnMap = {
  27:     "{urn:iControl}LocalLB.LBMethod" => 1,
  28:     "{urn:iControl}LocalLB.MonitorRuleType" => 1,
  29:     "{urn:iControl}LocalLB.ProfileContextType" => 1,
  30:     "{urn:iControl}LocalLB.ProfileType" => 1,
  31:     "{urn:iControl}LocalLB.VirtualServer.VirtualServerType" => 1,
  32: };
  33: sub SOAP::Deserializer::typecast
  34: {
  35:   my ($self, $value, $name, $attrs, $children, $type) = @_;
  36:   my $retval = undef;
  37:   if ( 1 == $urnMap->{$type} )
  38:   {
  39:     $retval = $value;
  40:   }
  41:   return $retval;
  42: }

Creating An Interface Object

Since I’m using several interfaces, I found it easier to write a wrapper subroutine to instantiate the appropriate iControl interface object, assign it the user credentials, and return to the caller.  This saves a lot of space when you are working multiple iControl interfaces.

   1: sub GetInterface()
   2: {
   3:   my ($module, $name) = @_;
   4:   
   5:   $interface = SOAP::Lite
   6:     -> uri("urn:iControl:$module/$name")
   7:     -> readable(1)
   8:     -> proxy("https://$BIGIP/iControl/iControlPortal.cgi");
   9:   eval { $interface->transport->http_request->header
  10:   ( 'Authorization' => 'Basic ' . MIME::Base64::encode("$User:$Pass", '') ); };
  11:  
  12:   return $interface;
  13: }

Querying The Configuration

The following code shows all the iControl calls needed to query the virtual servers configuration.  First, the LocalLB.get_list() method is called to get a list of virtual servers.  That list is then passed into the get_destination(), get_type(), get_rule(), get_profile(), get_persistence_profile(), and get_default_pool_name() methods.  The pool name list returned from the get_default_pool_name() method is then used as the input for the Pool.get_member(), get_lb_method(), and get_monitor_association() methods.

   1: $LocalLBVirtualServer = &GetInterface("LocalLB", "VirtualServer");
   2: $LocalLBPool = &GetInterface("LocalLB", "Pool");
   3: $LocalLBPoolMember = &GetInterface("LocalLB", "PoolMember");
   4:  
   5: # VS List
   6: $soapResponse = $LocalLBVirtualServer->get_list();
   7: &checkResponse($soapResponse);
   8: @vs_list = @{$soapResponse->result};
   9:  
  10: # Destination
  11: $soapResponse = $LocalLBVirtualServer->get_destination(
  12:   SOAP::Data->name (virtual_servers => [@vs_list])
  13: );
  14: &checkResponse($soapResponse);
  15: @destination_list = @{$soapResponse->result};
  16:  
  17: # Type
  18: $soapResponse = $LocalLBVirtualServer->get_type(
  19:   SOAP::Data->name (virtual_servers => [@vs_list])
  20: );
  21: &checkResponse($soapResponse);
  22: @vstype_list = @{$soapResponse->result};
  23:  
  24: # iRules
  25: $soapResponse = $LocalLBVirtualServer->get_rule(
  26:   SOAP::Data->name (virtual_servers => [@vs_list])
  27: );
  28: &checkResponse($soapResponse);
  29: @rule_listA = @{$soapResponse->result};
  30:  
  31: # Profiles
  32: $soapResponse = $LocalLBVirtualServer->get_profile(
  33:   SOAP::Data->name(virtual_servers => [@vs_list])
  34: );
  35: &checkResponse($soapResponse);
  36: @profile_listA = @{$soapResponse->result};
  37:  
  38: $soapResponse = $LocalLBVirtualServer->get_persistence_profile(
  39:   SOAP::Data->name(virtual_servers => [@vs_list])
  40: );
  41: &checkResponse($soapResponse);
  42: @persistenceprofile_listA = @{$soapResponse->result};
  43:  
  44: # Pools
  45: $soapResponse = $LocalLBVirtualServer->get_default_pool_name(
  46:   SOAP::Data->name (virtual_servers => [@vs_list])
  47: );
  48: &checkResponse($soapResponse);
  49: @pool_list = @{$soapResponse->result};
  50:  
  51: # Pool Members
  52: $soapResponse = $LocalLBPool->get_member(
  53:   SOAP::Data->name(pool_names => [@pool_list])
  54: );
  55: &checkResponse($soapResponse);
  56: @member_listA = @{$soapResponse->result};
  57:  
  58: # LB Method
  59: $soapResponse = $LocalLBPool->get_lb_method(
  60:   SOAP::Data->name(pool_names => [@pool_list])
  61: );
  62: &checkResponse($soapResponse);
  63: @lbmethod_list = @{$soapResponse->result};
  64:  
  65: $soapResponse = $LocalLBPool->get_monitor_association(
  66:   SOAP::Data->name(pool_names => [@pool_list])
  67: );
  68: &checkResponse($soapResponse);
  69: @monitor_list = @{$soapResponse->result};

At this point, we have the configuration stored in the various local variables and we are ready to print it in an XML format.

Generating the XML

The code below creates the XML declaration and the various elements that consist of the virtual server configuration.  We iterate through the virtual server list in the $vs_list variable to add an element for each virtual server.  The name, destination, and type are all stored as attributes of the element.

Then we iterate through the list of iRules associated with the given virtual server and output an element for each one containing the iRule name and priority.  This is followed by the list of profiles and persistence profiles for the current virtual server.

Next we will go through the pool members in the pool for the current virtual server.  An element is created for each pool containing the name and lb_method.  For each pool element, the pool members are then displayed as a child element with their address and port.

Finally, the monitors associated with the virtual server are presented.  The type of monitor association is given along with the quorum value and child entries for each monitor template is added.

   1: print "<?xml version='1.0'?>\n";
   2: print "<BIGIPConfig>\n";
   3: print "  <LTM>\n";
   4: for $i (0 .. $#vs_list)
   5: {
   6:   # vip
   7:   $vip = @vs_list[$i];
   8:   $pool = @pool_list[$i];
   9:   $destination = @destination_list[$i];
  10:   $vstype = @vstype_list[$i];
  11:   @rule_list = @{$rule_listA[$i]};
  12:   @profile_list = @{$profile_listA[$i]};
  13:   @persistenceprofile_list = @{$persistenceprofile_listA[$i]};
  14:  
  15:   # pool
  16:   @member_list = @{$member_listA[$i]};
  17:   $monitorassociations = @monitor_list[$i];
  18:   $monitor_rule = $monitorassociations->{"monitor_rule"};
  19:   $lb_method = $lbmethod_list[$i];
  20:  
  21:   $daddr = $destination->{"address"};
  22:   $dport = $destination->{"port"};
  23:   print "    <virtual_server name='$vip' destination='${address}:${port}' type='$vstype'>\n";
  24:   
  25:   for $j (0 .. $#rule_list)
  26:   {
  27:     $rule = @rule_list[$j];
  28:     $name = $rule->{"rule_name"};
  29:     $priority = $rule->{"priority"};
  30:     print "      <rule name='$name' priority='$priority'/>\n";
  31:   }
  32:   
  33:   for $j (0 .. $#profile_list)
  34:   {
  35:     $profile = @profile_list[$j];
  36:     $type = $profile->{"profile_type"};
  37:     $context = $profile->{"profile_context"};
  38:     $name = $profile->{"profile_name"};
  39:     print "      <profile name='$name' type='$type' context='$context'/>\n";
  40:   }
  41:   
  42:   for $j (0 .. $#persistenceprofile_list)
  43:   {
  44:     $pprofile = @persistenceprofile_list[$j];
  45:     $name = $pprofile->{"profile_name"};
  46:     $default = $pprofile->{"default_profile"};
  47:     print "      <persistenceprofile name='$name' default='$default'/>\n";
  48:   }
  49:   
  50:   print "      <pool name='$pool' lb_method='$lb_method'>\n";
  51:   for $j (0 .. $#member_list)
  52:   {
  53:     $member = @member_list[$j];
  54:     $address = $member->{"address"};
  55:     $port = $member->{"port"};
  56:     print "        <member addr='$address' port='$port'/>\n";
  57:   }
  58:   
  59:   $type = $monitor_rule->{"type"};
  60:   $quorum = $monitor_rule->{"quorum"};
  61:   @templates = @{$monitor_rule->{"monitor_templates"}};
  62:   print "        <monitors type='$type' quorum='$quorum'>\n";
  63:   for $j (0 .. $#templates)
  64:   {
  65:     $template = @templates[$j];
  66:     print "          <template name='$template'/>\n";
  67:   }
  68:   print "        </monitors>\n";
  69:   
  70:   print "      </pool>\n";
  71:   print "    </virtual_server>\n";
  72: }
  73: print "  </LTM>\n";
  74: print "</BIGIPConfig>\n";

The Output

Running the command on my test BIG-IP, results in the following XML output.

   1: <BIGIPConfig>
   2:   <LTM>
   3:     <virtual_server name='dc-sea-web' destination=':' type='RESOURCE_TYPE_POOL'>
   4:       <profile name='http' type='PROFILE_TYPE_HTTP' context='PROFILE_CONTEXT_TYPE_ALL'/>
   5:       <profile name='tcp' type='PROFILE_TYPE_TCP' context='PROFILE_CONTEXT_TYPE_ALL'/>
   6:       <pool name='dc-sea-web' lb_method='LB_METHOD_ROUND_ROBIN'>
   7:         <member addr='10.10.10.201' port='80'/>
   8:         <member addr='10.10.10.202' port='80'/>
   9:         <monitors type='MONITOR_RULE_TYPE_SINGLE' quorum='0'>
  10:           <template name='tcp'/>
  11:         </monitors>
  12:       </pool>
  13:     </virtual_server>
  14:     <virtual_server name='xpbert-ssh' destination='10.10.10.202:80' type='RESOURCE_TYPE_POOL'>
  15:       <profile name='tcp' type='PROFILE_TYPE_TCP' context='PROFILE_CONTEXT_TYPE_ALL'/>
  16:       <pool name='xpbert-ssh' lb_method='LB_METHOD_ROUND_ROBIN'>
  17:         <member addr='10.10.10.149' port='22'/>
  18:         <monitors type='MONITOR_RULE_TYPE_SINGLE' quorum='0'>
  19:           <template name='gateway_icmp'/>
  20:         </monitors>
  21:       </pool>
  22:     </virtual_server>
  23:     <virtual_server name='xpbert-http' destination='10.10.10.149:22' type='RESOURCE_TYPE_POOL'>
  24:       <rule name='calc_commands' priority='1'/>
  25:       <profile name='my_http' type='PROFILE_TYPE_HTTP' context='PROFILE_CONTEXT_TYPE_ALL'/>
  26:       <profile name='tcp' type='PROFILE_TYPE_TCP' context='PROFILE_CONTEXT_TYPE_ALL'/>
  27:       <profile name='ts_reputation' type='PROFILE_TYPE_STATISTICS' context='PROFILE_CONTEXT_TYPE_ALL'/>
  28:       <persistenceprofile name='source_addr' default='0'/>
  29:       <pool name='xpbert-http' lb_method='LB_METHOD_ROUND_ROBIN'>
  30:         <member addr='10.10.10.149' port='80'/>
  31:         <member addr='10.10.10.149' port='81'/>
  32:         <monitors type='MONITOR_RULE_TYPE_AND_LIST' quorum='0'>
  33:           <template name='gateway_icmp'/>
  34:           <template name='tcp'/>
  35:         </monitors>
  36:       </pool>
  37:     </virtual_server>
  38:   </LTM>
  39: </BIGIPConfig>

Parsing With External Tools

In the following example, I’ll pipe the output from the perl script directly into an XML variable in PowerShell.  PowerShell supports XML as a native type, so it’s very easy to look at the configuration like the following example:

   1: PS> [xml]$x = perl .\LtmConfigToXml.pl bigip user pass
   2: PS> $x.BIGIPConfig.LTM.virtual_server
   3:  
   4: name        : dc-sea-web
   5: destination : :
   6: type        : RESOURCE_TYPE_POOL
   7: profile     : {http, tcp}
   8: pool        : pool
   9:  
  10: name        : xpbert-ssh
  11: destination : 10.10.10.202:80
  12: type        : RESOURCE_TYPE_POOL
  13: profile     : profile
  14: pool        : pool
  15:  
  16: name               : xpbert-http
  17: destination        : 10.10.10.149:22
  18: type               : RESOURCE_TYPE_POOL
  19: rule               : rule
  20: profile            : {my_http, tcp, ts_reputation}
  21: persistenceprofile : persistenceprofile
  22: pool               : pool

Extending This Script

I’ve only scratched the surface with the configuration on the BIG-IP.  I picked a couple of the components of a virtual server so you may want to add to this for additional configuration objects that I omitted.  Also, other high level products like GTM could easily be added to this logic to create a more expansive coverage of the BIG-IP configuration.

Getting The Source

The full source for this application can be found in the iControl CodeShare Wiki under PerlLtmConfigToXml

Comments on this Article
Comment made 02-Jul-2012 by Larry Rice 3
Newbie at scripting on F5s...not sure if I did something wrong:
syntax error at /PerlLtmConfigToXml.pl line 54, near "sub SOAP::Transport::HTTP::Client::get_basic_credentials--"
Execution of /PerlLtmConfigToXml.pl aborted due to compilation errors.
0
Comment made 02-Jul-2012 by Larry Rice 3
great stuff though, looking forward to getting working. going to use to import info into DB for "live" documentation type stuff...EM is missing some key relationships for that.
Thanks much!
0
Comment made 14-Jan-2014 by Jim 0
This works fine for our 3600 but returns nothing for our Viprion. Any suggestions for modifying it to handle the Viprion?
0
Comment made 11-Apr-2014 by Alan Renicor 119
Excellent script and guide.
I did notice a slight error in the full source code at line 217
print " \n";

Should actually read:
print " \n";
Otherwise your output will show no ip/port for the first vip and each subsequent vip will actually show the last member pool from the previous vip.
Hope this helps. Had me confused for sometime.
0
Comment made 11-Apr-2014 by Alan Renicor 119
Line 217 should have the following
virtual_server name='$vip' destination='${daddr}:${dport}' type='$vstype'
0
Comment made 15-Apr-2015 by prt1969 174
Wouldn't it be easier just to support a web gui xml export instead like most other vendors? :)
0