Forum Discussion

Alexander_Stewa's avatar
Alexander_Stewa
Icon for Nimbostratus rankNimbostratus
May 02, 2007

Help with PoolMember get_object_status on dozens of pools

So I'm writing an iControl program in perl that essentially recreates the network map that was the main page of BigIP 4.x I have the following working:

All VIPs

Status of all VIPs

All Pools in each VIP

Status of all Pools

All Nodes (PoolMembers) in each pool.

The problem is getting the status of all PoolsMembers in each pool; not because I can't do so but rather because I have to make a new soap call for each Pool.


$soap -> uri ('urn:iControl:LocalLB/PoolMember');
my $PoolMemberStatus = $soap->get_object_status(SOAP::Data->name(pool_names => [$PoolName]),
 SOAP::Data->name(members => [@ArrayOfPoolMembers]));

We have ~150 Pools, so that's ~150 soaps calls, and this makes loading the page take like a minute which really defeats the purpose of getting the status of ever VIP/Pool/Node at a glance in real time.

So finally my question: Is there anyway to speed this up? Getting the status of all PoolMembers at the same time, or maybe sending multiple requests with only one Soap call?

Thanks,

Alex

8 Replies

  • Alex, all our methods in 9.x allow for multiple input values so you can pass in more than one pool name in a single request. In your example, you are passing in an array with only a single pool per call. One thing I'm also wondering about in your code sample is why you are passing in the members parameter since the PoolMember::get_object_status() method only takes a single parameter (list of pools).

     

     

    http://devcentral.f5.com/Wiki/default.aspx/iControl/LocalLB__PoolMember__get_object_status.html

     

    Click here

     

     

     

    MemberObjectStatus [] [] LocalLB:oolMember::get_object_status(
        in String [] pool_names
    );

     

     

    Here's some code that makes one call to get a list of all the pools, and then a second call to request the pool members statuses for all the pools.

     

     

    $Pool = SOAP::Lite
      -> uri('urn:iControl:LocalLB/Pool')
      -> readable(1)
      -> proxy("$sProtocol://$sHost:$sPort/iControl/iControlPortal.cgi");
    $PoolMember = SOAP::Lite
      -> uri('urn:iControl:LocalLB/PoolMember')
      -> readable(1)
      -> proxy("$sProtocol://$sHost:$sPort/iControl/iControlPortal.cgi");
    $soapResponse = $Pool->get_list();
    @pool_list = @{$soapResponse->result};
      
    $soapResponse = $PoolMember->get_object_status(
      SOAP::Data->name(pool_names => [@pool_list])
    );
    @member_object_status_AofA = @{$soapResponse->result};
      
    $i = 0;
    foreach $pool (@pool_list)
    {
      print "POOL $pool\n";
      @member_object_status_list = @{@member_object_status_AofA[$i]};
      foreach $member_object_status (@member_object_status_list)
      {
        $member = $member_object_status->{"member"};
        $address = $member->{"address"};
        $port = $member->{"port"};
        $object_status = $member_object_status->{"object_status"};
        $availability_status = $object_status->{"availability_status"};
        $enabled_status = $object_status->{"enabled_status"};
        $status_description = $object_status->{"status_description"};
          
        print "  MEMBER $address:$port\n";
        print "    $availability_status\n";
        print "    $enabled_status\n";
        print "    $status_description\n";
      }
      $i++;
    }

     

     

    So, no matter how many pools or members you have, it'll only take two calls.

     

     

    You can do similar things with virtuals and nodes. Also, look for the "get_all*" methods in some of the interfaces. That make help out with avoiding having to query a list first.

     

     

    Let me know if anything else comes up...

     

     

    -Joe
  • Thanks for the help Joe. I was running into this problem because I was looking at the API for GlobalLB instead of LocalLB accidently (even though I used LocalLB in my code).

     

     

    So I was confused since the GlobalLB API says:

     

     

    
    MemberObjectStatus[][] get_object_status(
        in String[] pool_names,
        in IPPortDefinition[][] members
    );

     

     

    Anyhow, I have now got it all working quickly and am very happy. Thanks again.

     

     

    -Alex

     

  • Great, glad things are looking up now... Please feel free to come back if any other issues come up. Chances are, if you are having a hard time with something, someone else is as well...

     

     

    -Joe
  • Hi I'm trying to getting started with Icontrol. Until now I'm very impressed about the features. Now I have a problem with the GlobalLBPoolMemberMemberObjectStatus[][] class. I have try to get the object_status of the pool Member in the pool I get followinf error:

     

     

    AxisFault

     

    faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server

     

    faultSubcode:

     

    faultString: Could not find element by name: address

     

    faultActor:

     

    faultNode:

     

    faultDetail:

     

     

    Probably I have a problem in my code.. Could you help me ??

     

     

    Hereby my class

     

     

    package com.casablanca.lb;
    /*
     * The contents of this file are subject to the "END USER LICENSE AGREEMENT FOR F5
     * Software Development Kit for iControl"; you may not use this file except in
     * compliance with the License. The License is included in the iControl
     * Software Development Kit.
     *
     * Software distributed under the License is distributed on an "AS IS"
     * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
     * the License for the specific language governing rights and limitations
     * under the License.
     *
     * The Original Code is iControl Code and related documentation
     * distributed by F5.
     *
     * The Initial Developer of the Original Code is F5 Networks,
     * Inc. Seattle, WA, USA. Portions created by F5 are Copyright (C) 1996-2004 F5
     * Inc. All Rights Reserved.  iControl (TM) is a registered trademark of F5 Netw
     *
     * Alternatively, the contents of this file may be used under the terms
     * of the GNU General Public License (the "GPL"), in which case the
     * provisions of GPL are applicable instead of those above.  If you wish
     * to allow use of your version of this file only under the terms of the
     * GPL and not to allow others to use your version of this file under the
     * License, indicate your decision by deleting the provisions above and
     * replace them with the notice and other provisions required by the GPL.
     * If you do not delete the provisions above, a recipient may use your
     * version of this file under either the License or the GPL.
     */
    import java.text.*;
    import java.util.*;
    import iControl.*;
    public class GlobalLBActivateNode extends Object
    {
    //--------------------------------------------------------------------------
    // Member Variables
    //--------------------------------------------------------------------------
    public String m_endpoint;
    public iControl.GlobalLBWideIPBindingStub m_nodeAddress;
      public iControl.GlobalLBPoolBindingStub m_pool; 
      public iControl.GlobalLBPoolMemberBindingStub m_poolMember; 
      public iControl.GlobalLBServerBindingStub m_server; 
      
    //--------------------------------------------------------------------------
    // Constructor
    //--------------------------------------------------------------------------
    public GlobalLBActivateNode()
    {
    System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.home") + "/.keystore");
    XTrustProvider.install();
    }
    //--------------------------------------------------------------------------
    // parseArgs
    //--------------------------------------------------------------------------
    public boolean parseArgs(String[] args) throws Exception
    {
    boolean bSuccess = false;
        
    if ( args.length < 4 )
    {
    usage();
    }
    else
    {
    // build parameters
    m_endpoint = "https://admin:protocom" + "@tcwe3s:443" + "/iControl/iControlPortal.cgi";
    m_nodeAddress = (iControl.GlobalLBWideIPBindingStub)
    new iControl.GlobalLBWideIPLocator().getGlobalLBWideIPPort(new java.net.URL(m_endpoint));
    m_pool= (iControl.GlobalLBPoolBindingStub)
    new iControl.GlobalLBPoolLocator().getGlobalLBPoolPort(new java.net.URL(m_endpoint));
    m_poolMember= (iControl.GlobalLBPoolMemberBindingStub)
    new iControl.GlobalLBPoolMemberLocator().getGlobalLBPoolMemberPort(new java.net.URL(m_endpoint));
    m_server= (iControl.GlobalLBServerBindingStub)
    new iControl.GlobalLBServerLocator().getGlobalLBServerPort(new java.net.URL(m_endpoint));
    m_nodeAddress.setTimeout(60000);
    m_pool.setTimeout(60000);
    m_poolMember.setTimeout(60000);
    bSuccess = true;
    if ( args.length >= 5 )
    {
    //getNodeInfo(new String[] {args[4]});
    }
    else
    {
    //getAllNodeInfo();
    getNodeList();
    }
    }
    return bSuccess;
    }
    //-------------------------------------------------------------------------
    //
    //--------------------------------------------------------------------------
    public void usage()
    {
    System.out.println("Usage: GlobalLBActivateNode hostname port username password [node_address]\n");
    }
    public String[] getPoolList() throws Exception
    {
    return m_pool.get_list();
    }
    public String[] getNodeList()throws Exception
    {
    return m_nodeAddress.get_list();
    }
    public String[] getServerList()throws Exception
    {
    return m_server.get_list();
    }
    public iControl.GlobalLBWideIPWideIPPool[][] getWideIPPool(String[] wide_ips)throws Exception
    {
    return m_nodeAddress.get_wideip_pool(wide_ips);
    }
    public iControl.CommonObjectStatus[] getObjectStatus(String[] node_list) throws Exception
    {
    iControl.CommonObjectStatus[] object_status_list =
    m_pool.get_object_status(node_list);
    return object_status_list;
    }
    public iControl.GlobalLBPoolMemberMemberObjectStatus[][] getPoolObjectStatus(String[] node_list,iControl.CommonIPPortDefinition[][] members) throws Exception
    {
    iControl.GlobalLBPoolMemberMemberObjectStatus[][] object_status_list =
    m_poolMember.get_object_status(node_list,members);
    return object_status_list;
    }
    public iControl.CommonEnabledState [] getStateInfo(String[] node_list) throws Exception
    {
    iControl.CommonEnabledState [] enabled_state_list =
    m_nodeAddress.get_enabled_state(node_list);
    return enabled_state_list;
    }
    public iControl.GlobalLBPoolPoolMemberDefinition[][] getPoolMember(String[] pool_list) throws Exception
    {
    iControl.GlobalLBPoolPoolMemberDefinition[][] pool_definition=
    m_pool.get_member(pool_list);
    return pool_definition;
    }
    //--------------------------------------------------------------------------
    // Main
    //--------------------------------------------------------------------------
    public static void main(String[] args)
    {
    try
    {
    iControl.CommonIPPortDefinition ipaddress=null;
    GlobalLBActivateNode globalLBActivateNode = new GlobalLBActivateNode();
    globalLBActivateNode.parseArgs(args);
    // pool list Array
    String pools [] = new String[globalLBActivateNode.getNodeList().length];
    iControl.GlobalLBWideIPWideIPPool[][] wideip=globalLBActivateNode.getWideIPPool(globalLBActivateNode.getNodeList());
    // get the wide ip list
    for(int i=0;ifor(int j=0;jSystem.out.println(wideip[ i ][j].getPool_name());
    // Get the pool list
    pools[ i ]=wideip[ i ][j].getPool_name();
    }
    }
    iControl.CommonIPPortDefinition [][] info;
        info = new iControl.CommonIPPortDefinition[pools.length][];
    iControl.GlobalLBPoolPoolMemberDefinition[][] members= globalLBActivateNode.getPoolMember(pools);
    for(int i=0;iinfo[ i ] = new iControl.CommonIPPortDefinition[i+1];     
    for(int j=0;jipaddress=members[ i ][j].getMember();
    // Fill the array with the CommonIPPortDefinition
    info[ i ][j] = new iControl.CommonIPPortDefinition(ipaddress.getAddress(),ipaddress.getPort());
      
    }
    }
     
    // Test if the return value ist PoolMember   
       System.out.println(globalLBActivateNode.getPoolObjectStatus(pools,info));
       
         
    }
    catch(Exception ex)
    {
    ex.printStackTrace(System.out);
    }
    }
    };

     

     

     

  • First of all, I modified your post to for formatting (hope you don't mind...). bracket-i-closebracket is formatted as an italic in our forum code.

     

     

    Now for your issue...

     

     

    Errors like "Could not find element by name" implies either 1) a serialization error on the client (most prevalent in dynamic languages like perl) or 2) a null element where a value was expected. The "address" field is most likely from the IPPortDefinition structure in the members parameter to get_object_status(). That would mean that you have some null fields in there.

     

     

    Taking a look at your code where you are allocating and filling in the "info" member, I noticed something odd:

     

     

    iControl.CommonIPPortDefinition [][] info;
    info = new iControl.CommonIPPortDefinition[pools.length][];
    iControl.GlobalLBPoolPoolMemberDefinition[][] members= globalLBActivateNode.getPoolMember(pools);
    for(int i=0;i  info[ i ] = new iControl.CommonIPPortDefinition[i+1];
      for(int j=0;j    ipaddress=members[ i ][ j ].getMember();
        // Fill the array with the CommonIPPortDefinition
        info[ i ][ j ] = new iControl.CommonIPPortDefinition(ipaddress.getAddress(),ipaddress.getPort());
      }
    }

     

     

    The line where you are allocating the 2nd dimension of the info array index i, you are allocating it to a size of i+1, but then you are entering a for loop from 0 to members[ i ].length-1. I think those two values should be the same. Odds are that i+1 will not always equal the members[ i ].length. I'm surprised you didn't get a runtime violation for the case when members[ i ].length was greater than i+1.

     

     

    I'd change your code to this and see if it fixes things up.

     

     

    iControl.CommonIPPortDefinition [][] info;
    info = new iControl.CommonIPPortDefinition[pools.length][];
    iControl.GlobalLBPoolPoolMemberDefinition[][] members= globalLBActivateNode.getPoolMember(pools);
    for(int i=0;i  info[ i ] = new iControl.CommonIPPortDefinition[members[ i ].length];
      for(int j=0;j    ipaddress=members[ i ][ j ].getMember();
        // Fill the array with the CommonIPPortDefinition
        info[ i ][ j ] = new iControl.CommonIPPortDefinition(ipaddress.getAddress(),ipaddress.getPort());
      }
    }

     

     

    I'm not sure this will totally fix your issue, but odds are it will get you going in the right direction.

     

     

    Let me know if this does or doesn't work and I'll dig into it some more...

     

     

    -Joe
  • Great! Glad to help...

     

     

    Please let us know if anything else comes up...

     

     

    -Joe