DX Infrastructure Management

 View Only

Perl SDK - Nimbus::PDS::asHash (Array refactoring) 

Jan 12, 2018 04:17 PM

Hi,

 

Recently, one of my customer identified a issue on my probe static_enrichment. Some parts of the SNMP-TRAP QoS was deleted by my probe and not republished on the final message. After few analyse of these QoS i identified that the deleted parts of each PDS was an Array Type ( PDS_PPCH or PDS_PPI type most of the time). 

 

First i was thinking that my method to transform an Hash into a PDS introduced a issue (but no !   ).

 

My problem was at the level of PDS->asHash() method. asHash() only return the first "key" value of each PDS array.

 

Take this example : 

use strict;
use Data::Dumper;

# Use Nimsoft (Nimbus) lib
use lib "/opt/nimsoft/perllib";
use lib "/opt/nimsoft/perl/lib";
use Nimbus::API;
use Nimbus::PDS;

my $PDS = Nimbus::PDS->new();
$PDS->putTable('STR_ARRAY', 'hello', PDS_PCH);
$PDS->putTable('STR_ARRAY', 'world!', PDS_PCH);
$PDS->putTable('INTEGER_ARRAY', '5', PDS_INT);
$PDS->putTable('INTEGER_ARRAY', '10', PDS_INT);

$PDS->dump();
print Dumper($PDS->asHash())."\n";

 

It produce the following output : 

STR_ARRAY       PDS_PPCH         25
0               PDS_PCH           6 hello
1               PDS_PCH           7 world!
INTEGER_ARRAY   PDS_PPI          17
0               PDS_I             2 5
1               PDS_I             3 10


$VAR1 = {
    'STR_ARRAY' => '0',
    'INTEGER_ARRAY' => '0'
};

 

Yeah ... Not really what we want right?

 

So i started a refactoring of the asHash method in the PDS.pm file. Take a look at my newest version :  

1. Renaming of variables because original one was not clear at all...

2. Optimize code 

3. Change nimLog level (2 is not enougth for a "debug" / "info" statment). Four should be the best value for me ...

 

use constant {
    PDS_PPCH => 8,
    PDS_PPI => 3
};

sub asHash {
     my $self = shift;
     my $hptr = shift || {};
     my $pds  = shift || $self->{pds};
     my $lev  = shift || 1;

     my ($rc, $key, $type, $s, $value);
     my $line = "-" x $lev;
     while($rc == 0) {
          ($rc, $key, $type, $size, $value) = pdsGetNext($pds);
          next if $rc != PDS_ERR_NONE;
          # print "PDS Type => $type, key => $key, value => $value, size => $size\n";
          if ($type == PDS_PDS) {
               if (!defined($hptr->{$key})) {
                    nimLog(3,"PDS::asHash $line>Adding PDS: $key\n");
                    $hptr->{$key} = {};
               }
               asHash($self, $hptr->{$key}, $value, $lev + 1);
               pdsDelete($value);
          }
          elsif ($type == PDS_PPCH || $type == PDS_PPI) {
               nimLog(3,"PDS::asHash $line>Adding Array: $key\n");
               my $tableIndex = 0;
               my @tableValues = ();
               my ($rc_table, $rd);
               WPDS_PCH: while($rc_table == 0) {
                    ($rc_table, $rd) = pdsGetTable($pds, PDS_PCH, $key, $tableIndex);
                    last WPDS_PCH if $rc_table != PDS_ERR_NONE;
                    push(@tableValues, $rd);
                    $tableIndex++;
               };
               $hptr->{$key} = \@tableValues;
          }
          else {
               nimLog(3, "PDS::asHash $line>Adding key/value: $key = $value");
               $hptr->{$key} = $value;
          }
     };
     return $hptr;
}

 

At first there is two new PDS Constants to add to the SDK ( INT 8 for PDS_PPCH and INT 3 for PDS_PPI ). After that the only thing to do is to add a new elsif to match these two types ! 

There is some cases not supported (Like PDS_PDS in PDS_PPCH or things like that). I think it should be possible to add a support for PDS_PPDS type too ... 

 

Note : The Nimbus::PDS::getTable is useless and doesn't work as expected too... I will surely rebuild a complete high level PDS class to work with soon ! 

 

And now my script stdout is matching my expectation : 

$VAR1 = {
    'STR_ARRAY' => [
        'hello',
        'world!'
    ],
    'INTEGER_ARRAY' => [
        '5',
        '10'
    ]
};

 

And there is no more issue with my probe ! 

 

Hope this article will help someone one day

 

Best Regards,

Thomas

Statistics
0 Favorited
2 Views
1 Files
0 Shares
0 Downloads
Attachment(s)
zip file
PDS.pm.zip   2 KB   1 version
Uploaded - May 29, 2019

Tags and Keywords

Comments

Apr 20, 2018 03:43 PM

Hi,

 

I'm back with a new code patch and bring some other problems  

 

I'v reworked my code to support PDS_PPDS as well. I tried to add FLOAT type but the PDS API to put a table of Float (PDS_F) doesn't work.

 

For example

my $F_PDS = pdsCreate();
pdsPutTable($F_PDS, PDS_F, "FLOAT_ARR", "0.5");
pdsPutTable($F_PDS, PDS_F, "FLOAT_ARR", "0.8");
pdsDump($F_PDS);

 

Not sure if this is a limitation of PDS or an implementation problem (On some API documentation, that seem possible to create an Array of FLOAT). Maybe when the PDS was implemented on Perl, it was considered useless because of the low "type" level of Perl (everything is SCALAR). But that mean : 

 

- We can't handle FLOAT Array

- We can't publish FLOAT Array.

 

That's a problem for some third-party perl probe like static_enrichment where i have to re-publish the message has it was at the beginning.

 

Let's back to our original subject (better asHash() implementation for Nimbus::PDS).

 

sub asHash {
     my $self = shift;
     my $hptr = shift || {};
     my $pds  = shift || $self->{pds};
     my $lev  = shift || 1;
     my ($rc, $k, $t, $s, $d);
    my $line = "-"x$lev;

     while ($rc == 0) {
          ($rc, $k, $t, $s, $d) = pdsGetNext($pds);
        next if $rc != PDS_ERR_NONE;
        if ($t == PDS_PDS) {
            if (!defined($hptr->{$k})) {
                nimLog(2,"PDS::asHash $line>Adding PDS: $k\n");
                $hptr->{$k}={};
            }
            asHash($self,$hptr->{$k},$d,$lev+1);
            pdsDelete($d);
        }
        elsif ($t == PDS_PPCH || $t == PDS_PPI) {
            nimLog(2,"PDS::asHash $line>Adding PDS_PPCH/PDS_PPI Array: $key\n");
            my @ret = ();
            for ( my $index = 0; my ($rc_table, $rd) = pdsGetTable($pds, PDS_PCH, $k, $index); $index++ ) {
                last if $rc_table != PDS_ERR_NONE;
                push(@ret, $rd);
            }
            $hptr->{$k} = \@ret;
        }
        elsif ($t == PDS_PPDS) {
            nimLog(2,"PDS::asHash $line>Adding PDS_PPDS Array: $key\n");
            my @ret = ();
            for ( my $index = 0; my ($rc_table, $rd) = pdsGetTable($pds, PDS_PDS, $k, $index); $index++ ) {
                last if $rc_table != PDS_ERR_NONE;
                push(@ret, Nimbus::PDS->new($rd)->asHash);
            }
            $hptr->{$k} = \@ret;
        }
        else {
            nimLog(2,"PDS::asHash $line>Adding key/value: $k = $d");
            $hptr->{$k} = $d;
        }
     };
     return $hptr;
}

 

This time i use the original log level and variable name of the initial implementation (because we have a CA Support case open around this subject).

 

I added some constant at the top of the script as well :

use constant {
    PDS_PPCH => 8,
    PDS_PPI => 3,
    PDS_PPDS => 24
};

 

So now we can retrieve an Array of PDS

 

my $PDS = Nimbus::PDS->new();

my $PDS_A = Nimbus::PDS->new();
$PDS_A->string("foo", "bar");

my $PDS_B = Nimbus::PDS->new();
$PDS_B->string("hel", 5);

$PDS->putTable('TEST', $PDS_A, PDS_PDS);
$PDS->putTable('TEST', $PDS_B, PDS_PDS);

print STDOUT Dumper($PDS->asHash())."\n";
# STOUT:
# $VAR1 = {
#     'TEST' => [
#         { 'foo' => 'bar' },
#         { 'hel' => '5' }
#     ]
# };

 

Best Regards,

Thomas

Jan 13, 2018 02:40 PM

Thx Thomas.

Well done.

Regards

Filippo Casati

 

 

 

Inviato da smartphone Samsung Galaxy.

Jan 13, 2018 01:58 PM

Hey! Good catch Thomas! Thanks for having thought of sharing this. I guess Perluim is going to improve again a bit soon!  Well done!

Related Entries and Links

No Related Resource entered.