Forum Discussion

GavinW_29074's avatar
GavinW_29074
Icon for Nimbostratus rankNimbostratus
Apr 26, 2012

Struggling with Perl and iControl?!

Hi there,

 

 

I'm trying to set-up a perl client for iControl to stream-line some of our processes.

 

 

I've got a very simply script which is based on one of the examples already provided. However I'm having issues with the following error:

 

Can't call method "fault" on an undefined value at f5_icontrol.pl.

 

 

Code looks like this. I've snipped some bits out that aren't relevant:

 

!/usr/bin/perl
use Getopt::Long;
use Switch;
use SOAP::Lite + trace => qw(debug);
use SOAP::Lite;
use MIME::Base64;
use Math::BigInt;
use Data::Dumper;
use FindBin;
use lib "$FindBin::Bin/../lib";
use iControlTypeCast;
 Disable SSL Certificate Verification
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
----------------------------------------------------------------------------
 Validate Arguments
----------------------------------------------------------------------------
 Define varaibles
my ($sHost, $sPort, $sUID, $sPWD, $sMode, $action, $filename );
 Pickup Run-Time Options
GetOptions (
    "sHost=s" => \$sHost,
    "sPort=i" => \$sPort,
    "sUID=s" => \$sUID,
    "sPWD=s" => \$sPWD,
    "sMode:s" => \$sMode,
    "action:s" => \$action,
    "filename:s" => \$filename
    );
 Assume always HTTPS
my $sProtocol = "https";
if ( ("80" eq $sPort) or ("8080" eq $sPort) )
{
  $sProtocol = "http";
}
if ( ($sHost eq "") or ($sPort eq "") or ($sUID eq "") or ($sPWD eq "") )
{
  &usage();
}
sub usage()
{
  my ($sCmd) = @_;
  print "Usage: CertInfo.pl --sHost host --sPort port --sUID username --sPWD password --action [script action] --filename [filename] \n";
  exit();
}
----------------------------------------------------------------------------
 Transport Information
----------------------------------------------------------------------------
sub SOAP::Transport::HTTP::Client::get_basic_credentials
{
  return "$sUID" => "$sPWD";
}
 Action Code
switch ($action) {
    case 'ci' { &GetCertInfo($sMode) }
    case 'im' { &ImportCert($sMode, $filename) }
    case 'ial' { &GetiAppList }
    case 'cf' { &GetCurrentFolder }
    else { print "Specified check not found ($action) \n" }
}
;
sub createHandler ($) 
{
    my ($uri) = shift;
    
    my ($handler) = SOAP::Lite
          -> uri($uri)
          -> proxy("$sProtocol://$sHost:$sPort/iControl/iControlPortal.cgi");
    eval { $KeyCertificateHandler->transport->http_request->header
    (
      'Authorization' => 
        'Basic ' . MIME::Base64::encode("$sUID:$sPWD", '')
    ); };
    
    return $handler;
}
sub GetCurrentFolder()
{
    
    my ($ws_uri) = 'urn:iControl:System/Session';
    
    my ($ws_handler) = createHandler($ws_uri);
    my ($soapResonse) =  $ws_handler->get_active_folder();
    &checkResponse($soapResponse);
    
    my $folder = $soapResponse->result();
    print "Current Folder = $folder \n";
    
}

 

 

With SOAP::Lite debug on, I can see the following output when running the script:

 

D:\Workspace\F5_iControl\bin>perl f5_icontrol.pl --sHost xxx --sPort 443 --sUID gavinw --sPWD xxx --a

 

ction cf

 

SOAP::Transport::HTTP::Client::send_receive: POST https://xxx:443/iControl/iControlPortal.cgi HTTP/1.1

 

Accept: text/xml

 

Accept: multipart/*

 

Accept: application/soap

 

Content-Length: 439

 

Content-Type: text/xml; charset=utf-8

 

SOAPAction: "urn:iControl:System/Sessionget_active_folder"

 

 

="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" soap:encodingStyle="http://sch

 

emas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">lns="urn:iControl:System/Session" xsi:nil="true" />

 

SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK

 

Connection: close

 

Date: Thu, 26 Apr 2012 09:36:04 GMT

 

Server: Apache

 

...

 

 

xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"

 

xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"

 

xmlns:s="http://www.w3.org/2001/XMLSchema-instance"

 

xmlns:y="http://www.w3.org/2001/XMLSchema"

 

xmlns:iControl="urn:iControl"

 

E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

 

 

xmlns:m="urn:iControl:System/Session">

 

s:type="y:string">/Common

 

 

 

 

Can't call method "fault" on an undefined value at f5_icontrol.pl line .

 

 

That quite clearly shows a valid response being returned...

 

 

So where am I going wrong???

 

 

Cheers

 

Gavin

 

8 Replies

  • Your response is fine, but you seem to have a typo?

     

     

    my ($soapResonse) = $ws_handler->get_active_folder();

     

    &checkResponse($soapResponse);

     

     

    You're calling &checkresponse with a with a variable that is missing a "p", hence the "fault" error reference.

     

     

    Hope this helps.

     

     

    Cheers

     

     

    Ross
  • Posted By Ross on 04/26/2012 02:57 AM

     

    Your response is fine, but you seem to have a typo?

     

     

    my ($soapResonse) = $ws_handler->get_active_folder();

     

    &checkResponse($soapResponse);

     

     

    You're calling &checkresponse with a with a variable that is missing a "p", hence the "fault" error reference.

     

     

    Hope this helps.

     

     

    Cheers

     

     

    Ross

     

    Talk about not being able to see the wood for the trees...

     

     

    Cheers for spotting that one Ross...

     

     

    Guna have to turn on strict I think...

     

     

    As a general comment, I think it would be better if the examples provided by F5 used strict in their perl examples :)

     

     

    Cheers

     

    Gavin

     

  • Another quick one from me then - Is it necessary/beneficial to close iControl sessions once finished with them?

     

     

    Cheers

     

    Gavin
  • Hehe, I know what you mean, I've done the same several times.

     

     

    Not sure on closing icontrol sessions, I generally dont. But then if you are changing active partitions/folders you may find that this persists if you dont close the session appropriately. (I've not looked into it too deeply, but have found a few instances where set_active_partition appears to "stick" but that may be just me).

     

     

    Cheers

     

     

    Ross
  • Posted By Ross on 04/26/2012 05:34 AM

     

    Hehe, I know what you mean, I've done the same several times.

     

     

    Not sure on closing icontrol sessions, I generally dont. But then if you are changing active partitions/folders you may find that this persists if you dont close the session appropriately. (I've not looked into it too deeply, but have found a few instances where set_active_partition appears to "stick" but that may be just me).

     

     

    Cheers

     

     

    Ross

     

    Ross

     

     

    Yeh, I was noticing the same thing when enabling the Recursive flag...

     

     

    Was looking through the SDK and couldn't find a way of 'logging out' or invalidating the session though, unless I missed something...

     

     

    Another question then, and this again relates to the Recursive flag...

     

     

    Is there a way that I can temporarily change the URI that a SOAP::Lite handler is using without having to change it back again?

     

    I.e. Currently I've got the following code block which handles setting of the recursive flag, and I'm having to set the URI after updating the recursive flag. This is fine in this scenario, but could prove awkward when constantly switching between URI's...

     

     

    sub createHandler ($$) 
    {
        my ($urn,$recursive) = (@_);
        
         Set-up variable
        my ($handler);
        
        if ($recursive) 
        {
            $handler = SOAP::Lite
                  -> proxy("$sProtocol://$sHost:$sPort/iControl/iControlPortal.cgi");
            eval { $handler->transport->http_request->header
            (
              'Authorization' => 
                'Basic ' . MIME::Base64::encode("$sUID:$sPWD", '')
            ); };    
            
             Set recursive
            &setRecursive($handler);
            
             Correct Handler URI path.
            $handler->uri($urn);
            
        } else {
            $handler = SOAP::Lite
                  -> uri($urn)
                  -> proxy("$sProtocol://$sHost:$sPort/iControl/iControlPortal.cgi");
            eval { $handler->transport->http_request->header
            (
              'Authorization' => 
                'Basic ' . MIME::Base64::encode("$sUID:$sPWD", '')
            ); };
        }
        
        return $handler;
    }
    ----------------------------------------------------------------------------
     setRecursive - Set the Recursive Query State. 
    ----------------------------------------------------------------------------
    sub setRecursive ($$) 
    {
        my ($handler) = (@_);
        
         Switch to System/Session and Set recursive
        $handler->uri('urn:iControl:System/Session')
                ->set_recursive_query_state(
                    SOAP::Data->name(state => "STATE_ENABLED")
                );
        
        return $handler;
    }

     

     

    Cheers

     

    Gav

     

  • Hi all, there were a couple of questions there so I'll try to hit them all.

     

     

    Regarding "sessions": iControl is a stateless API. Each call is a separate HTTP connection and there is really no concept of a "user session". But, with that being said, there are some persistent variables set within the server process that live for the live of that process. They are stored on a per-user basis and are things like the current Partition and, as you've found, the recursive flag for folders. It's probably best practice, if you are having multiple applications using the same user name, to set values back to the original values after you have set them. It's not required and is really dependent on the needs of your automation. Keep in mind that you can't guarantee that changes you make will be there later (if a reboot or restart happens). I'd have your script check and set whatever values you are expecting to use during that sequence of calls.

     

     

    As for the URI's, we've created our API with a separate namespace for each "interface" in our APIs. In my scripts, I've always just created multiple variables for each namespace you are accessing. ie. $LocalLBPool, $SystemSession, etc. That way when you are calling a method on that variable it's clear what interface it's going to. That's just me though. If you want to reuse the variables, then you'll have to change the namespace/url in between method calls.

     

     

    -Joe

     

  • Joe/Ross

     

     

    Cheers for your replies...

     

     

    I was trying to avoid creating multiple handlers to keep things cleaner. However like you say, it does add some additional complexity...

     

     

    Going back to the session issue, I guess another option would be to set the session timeout to a relatively low value so that it times out after the script completes?

     

     

    Cheers again.

     

    Gavin