Perl Issue trying to add static text by IP address - perl

I have a script that has an exact count of IP address' being compared to an expected count of IP address going though a specific port.
Code:
my %minimum = (
'10.10.10.10' => 2,
'10.10.10.11' => 3,
'10.10.10.12' => 6,
'10.10.10.13' => 7,
);
my %count;
open my $fh, '-|', 'netstat -an |grep 1111 ' or die "could not run netstat: $!";
while(<$fh>) {
next unless /^\s*............(regex) /;
$count{$1}++;
}
close $fh;
while(my ($ip, $expected) = each %minimum) {
$count{$ip} ||= 0;
next if $count{$ip} == $expected && print color("green"), "$ip: OK! Expected = $expected count = $count{$ip}\n", color("reset");
print color("red"), "$ip: BAD! Expected = $expected count = $count{$ip}\n", color("reset");
}
I'm trying to add a static hostname. Currently an example output looks like:
10.10.10.10: OK! Expected = 2 Actual = 2
10.10.10.11: OK! Expected = 3 Actual = 3
10.10.10.12: OK! Expected = 6 Actual = 6
10.10.10.13: BAD! Expected = 7 Actual = 5
But I want to include a static hostname to look like below:
10.10.10.10: aaaa#aa.com OK! Expected = 2 Actual = 2
10.10.10.11: bbb#aa.com OK! Expected = 3 Actual = 3
10.10.10.12: ccc#aa.com OK! Expected = 6 Actual = 6
10.10.10.13: ddd#aa.com BAD! Expected = 7 Actual = 5
Thank you all for any recommendations/tips.

You could create a second hash to keep the info, keyed on the ip addresses, or you could create a nested data structure like so:
my %minimum = (
'10.10.10.10' => { label => 'hotdog', count => 2 },
'10.10.10.11' => { label => 'burger', count => 3 },
'10.10.10.12' => { label => 'steak', count => 6 },
'10.10.10.13' => { label => 'pizza', count => 7 },
);
and then later, when you need the info, you can retrieve it:
while(my ($ip, $data) = each %minimum) {
$count{$ip} ||= 0;
my $label = $data->{label};
my $expected = $data->{count};
# ... rest of code here ...
}

my %notes = (
'10.10.10.10' => 'cheeseburger',
'10.10.10.11' => 'hotdog',
'10.10.10.12' => '...',
'10.10.10.13' => '...',
);
s{^([^:]*):\K}{ defined($notes{$1}) ? " $notes{$1}" : "" }e;

Related

Hash reference - Reuse inner hash to store and retrieve next values

I am new to Perl programming and have to work on Hash of Hashes. I am trying to reuse innerHash variables to be dynamic in nature. And I expect the inner items to be stored in outerHash how ever many I have added. Below is my test program snippet.
use warnings;
sub testHash {
my %outerHash = ();
my %innerHash1 = ();
my %innerHash2 = ();
$innerHash1{"key1"} = "value1";
$innerHash1{"key2"} = "value2";
$innerHash1{"key3"} = "value3";
$outerHash{"Master1"} = \%innerHash1;
$innerHash2{"key4"} = "value4";
$innerHash2{"key5"} = "value5";
$innerHash2{"key6"} = "value6";
$outerHash{"Master2"} = \%innerHash2;
#delete $innerHash1{$_};
%innerHash1 = ();
#undef %innerHash1;
$innerHash1{"key7"} = "value7";
$innerHash1{"key8"} = "value8";
$innerHash1{"key9"} = "value9";
$outerHash{"Master3"} = \%innerHash1;
foreach $outerItem (keys %outerHash){
print "\n$outerItem: ";
foreach $innerItem (keys %{$outerHash{$outerItem}}){
print "\t $innerItem = $outerHash{$outerItem}{$innerItem}";
}
print "\n-------------------------------------------------------";
}
print "\n";
}
testHash;
Output:
Master3: key8 = value8 key7 = value7 key9 = value9
-----------------------------------------------------------------
Master2: key5 = value5 key6 = value6 key4 = value4
-----------------------------------------------------------------
Master1: key8 = value8 key7 = value7 key9 = value9
-----------------------------------------------------------------
I understand it's taking the newer reference of innerHash1 while printing the items. What is the right way to have all the right elements in outerHash? In a real programming scenario I cannot declare n variables in advance.
You may be new to perl, but you understand the concept of pointers don't you? The code $outerHash{"Master1"} = \%innerHash1; means that "$outerHash{"Master1"} is assigned a pointer to %innerHash1". So what you're observing is correct and expected.
If you want to keep recreating %innerHash and adding it to %outerHash, you will need to do one of two things:
Assign by value. $outerHash{"Master1"} = {}; %{$outerHash{"Master1"}} = %innerHash1;
Only add %innerHash to %outerHash once per loop. Since %innerHash is redeclared within the loop, not outside of it, it goes out of scope every loop, but its contents will be kept in outerHash due to perl's reference counting. Depending on your perspective, this could be considered "trying to be too clever and potentially dangerous", but I think it's fine.
The "right" way, at least in my opinion, is by never declaring any intermediary "innerhashes" at all. Just use references directly:
my %outerHash;
$outerHash{Master1} = { key1 => 'value1', key2 => 'value2', key3 => 'value3'};
$outerHash{Master2} = { key4 => 'value4', key5 => 'value5', key6 => 'value6'};
$outerHash{Master3} = { key7 => 'value7', key8 => 'value8', key9 => 'value9'};
# or....
my %outerHash2;
$outerHash2{Master1}{key1} = 'value1';
$outerHash2{Master1}{key2} = 'value2';
$outerHash2{Master1}{key3} = 'value3';
$outerHash2{Master2}{key4} = 'value4';
$outerHash2{Master2}{key5} = 'value5';
$outerHash2{Master2}{key6} = 'value6';
$outerHash2{Master3}{key7} = 'value7';
$outerHash2{Master3}{key8} = 'value8';
$outerHash2{Master3}{key9} = 'value9';
# or...
my %outerHash3 = (
Master1 => {
key1 => 'value1',
key2 => 'value2',
key3 => 'value3'
}
Master2 => {
key4 => 'value4',
key5 => 'value5',
key6 => 'value6'
}
Master3 => {
key7 => 'value7',
key8 => 'value8',
key9 => 'value9'
}
);

Why is the server returned the result for a different submit than selected by perl HTML::Form and LWP::UserAgent?

I want to process a number of files with http://2struc.cryst.bbk.ac.uk/twostruc; to automate this I wrote a perl script using perl's HTML::Form.
This server has a two step submit process: first, upload a file or enter an id; second, select the methods to be used and the output (by chosing one of five submits).
The first step works, but for the second step I seem to be unable to chose any submit button other than the first, even though my script output confirms that I selected the one I want (different from the first).
The two core parts of the code are below, the request function:
sub create_submit_request
{
my $form_arrayref = shift;
my $form_action = shift;
my $value_hashref = shift;
my $submit_name = shift;
my $submit_index = shift;
my $found_form = 0;
my $form;
foreach my $this_form( #$form_arrayref)
{
printf( "# Found form with action=%s\n", $this_form->action);
if( $this_form->action eq $form_action)
{
$found_form = 1;
$form = $this_form;
}
}
die( "# Error: No form with action $form_action") if( $found_form == 0);
my #inputs = $form->inputs;
my $inputs_string;
foreach my $input( #inputs)
{
my $input_name = defined( $input->name) ? $input->name : "<unnamed_input>";
my $input_value = defined( $input->value) ? $input->value : "";
$inputs_string .= $input_name.( length( $input_value) > 0 ? "=".$input_value : "")." (".$input->type."); ";
}
printf( "# Available input names: %s\n", $inputs_string);
printf( "# Filling in form data\n");
while( my( $key, $value) = each( %$value_hashref))
{
$form->value( $key, $value);
}
my #submit_buttons = $form->find_input( $submit_name, "submit", $submit_index); # 1-based counting for the index
die( "# Error: Can only handle a single submit, but found ".scalar( #submit_buttons)) if( scalar( #submit_buttons) != 1);
my %submit_hash = %{ $submit_buttons[ 0]};
# DEBUG
printf( "# Use submit: %s\n", Data::Dumper->Dump( [ \%submit_hash ]));
return $form->click( %submit_hash);
}
and the code using it:
my $request = HTTP::Request->new( GET => $url_server);
my $response = $useragent->request( $request);
# the first page contains the pdb id input and file upload inputs
my #forms = HTML::Form->parse( $response);
my %value_hash = ( "file" => $pdb_file);
# the submit buttons have no name, use undef; chose the first one (w/o javascript)
$request = create_submit_request( \#forms, $form_action1, \%value_hash, undef, 1);
printf( "# Submitting to server\n");
$response = $useragent->request( $request);
# the first page contains the pdb id input and file upload inputs
#forms = HTML::Form->parse( $response);
%value_hash =( "dsspcont" => "on", "stride" => "on");
# this form has 5 submit buttons; select the 5th
$request = create_submit_request( \#forms, $form_action2, \%value_hash, undef, 5);
printf( "# Submitting to server\n");
$response = $useragent->request( $request);
my $response_content = $response->content;
printf( "# Response content: %s\n", $response_content);
Even though the script prints
# Use submit: $VAR1 = {
'name' => 'function_sequenceStructureAlignment',
'onclick' => 'this.form.target=\'_blank\';return true;',
'type' => 'submit',
'value' => 'Sequence Structure Alignments',
'value_name' => ''
};
which is the 5th submit button in the second step, the response is equivalent to pressing the first submit button.
To test the server itself, the file 1UBI.pdb can be downloaded from http://www.rcsb.org/pdb/files/1UBI.pdb and uploaded to the server. The full script is at http://pastebin.com/bSJLvNfc and can be run with
perl 2struc.pl --pdb 1UBI.pdb
Why is the server returning a different output/submit that I seem to select in the script?
(It seems it's not dependend on cookies, because I can clear them after the first step, and still get the correct result for the second step in a web browser.)
You gave a hash as selector for click, which is wrong (see documentation how to specify the selector). But because you have already found the correct submit element you could simply call click directly on it:
--- orig.pl
+++ fixed.pl
## -87,7 +87,7 ##
# DEBUG
printf( "# Use submit: %s\n", Data::Dumper->Dump( [ \%submit_hash ]));
- return $form->click( %submit_hash);
+ return $submit_buttons[0]->click($form);
}
sub predict_pdb

Perl using Win32::PerfLib

I'm trying to understand Win32::PerfLib better, and I mustn't use Win32::PerfMon.
Two example I have questions about:
First example, is the classic from CPAN:
use Win32::PerfLib;
my $server = "";`enter code here`
Win32::PerfLib::GetCounterNames($server, \%counter);
%r_counter = map { $counter{$_} => $_ } keys %counter;
# retrieve the id for process object
$process_obj = $r_counter{Process};
# retrieve the id for the process ID counter
$process_id = $r_counter{'ID Process'};
# create connection to $server
$perflib = new Win32::PerfLib($server);
$proc_ref = {};
# get the performance data for the process object
$perflib->GetObjectList($process_obj, $proc_ref);
$perflib->Close();
$instance_ref = $proc_ref->{Objects}->{$process_obj}->{Instances};
foreach $p (sort keys %{$instance_ref})
{
$counter_ref = $instance_ref->{$p}->{Counters};
foreach $i (keys %{$counter_ref})
{
if($counter_ref->{$i}->{CounterNameTitleIndex} == $process_id)
{
printf( "% 6d %s\n", $counter_ref->{$i}->{Counter},
$instance_ref->{$p}->{Name}
);
}
}
}
Could someone explain in depth the 4th line?
I didn't understand why we use $_ for and
what it represents, although I read about it
but in this case I don't know. In addition
what's the $counter{$_} => $_ meaning?
Second question is from this code, which gets the cpu %
from perfmon:
use Win32::PerfLib;
($server) = #ARGV;
# only needed for PrintHash subroutine
#Win32::PerfLib::GetCounterNames($server, \%counter);
$processor = 238;
$proctime = 6;
$perflib = new Win32::PerfLib($server);
$proc_ref0 = {};
$proc_ref1 = {};
$perflib->GetObjectList($processor, $proc_ref0);
sleep 5;
$perflib->GetObjectList($processor, $proc_ref1);
$perflib->Close();
$instance_ref0 = $proc_ref0->{Objects}->{$processor}->{Instances};
$instance_ref1 = $proc_ref1->{Objects}->{$processor}->{Instances};
foreach $p (keys %{$instance_ref0})
{
$counter_ref0 = $instance_ref0->{$p}->{Counters};
$counter_ref1 = $instance_ref1->{$p}->{Counters};
foreach $i (keys %{$counter_ref0})
{
next if $instance_ref0->{$p}->{Name} eq "_Total";
if($counter_ref0->{$i}->{CounterNameTitleIndex} == $proctime)
{
$Numerator0 = $counter_ref0->{$i}->{Counter};
$Denominator0 = $proc_ref0->{PerfTime100nSec};
$Numerator1 = $counter_ref1->{$i}->{Counter};
$Denominator1 = $proc_ref1->{PerfTime100nSec};
$proc_time{$p} = (1- (($Numerator1 - $Numerator0) /
($Denominator1 - $Denominator0 ))) * 100;
printf "Instance $p: %.2f\%\n", $proc_time{$p};
}
}
}
Why does the programmer had to use the method "GetObjectList"
Two times and put the sleep method between them?
And why we can't just take the cpu percent like perfmon shows
and we have to make all those calculations?
Thanks in advance,
Fam Pam.
In this code:
Win32::PerfLib::GetCounterNames($server, \%counter);
%r_counter = map { $counter{$_} => $_ } keys %counter;
You are stroing the perfdata in %counter hash. The map in this case creates a reverse hash where the earlier values becomes keys.
Example:
from apple => 'fruit' to fruit => 'apple

COnverting atime from LDAP to Perl

I have created a script in Perl to connect to LDAP, retrieve values and post them to a CSV file. The values I am retrieving via a query are d"distinguished name, userAccountControl & pwdLastSet. I can pull and parse the first two results correctly and post them to the CSV file, but the pwdLastSet is returning WIN32::OLE=HASH(0x.......). I have tired sprintf, hex(), and the results are either the WIN32 value or 0. I am expecting something 18 digits in length. Thanks for the help.
#!/usr/bin/perl
use xSV;
use Win32;
use Win32::OLE;
# use strict;
.
.
.
.
while ($line = <GROUPS>) {
chomp($line);
if ($line =~ m/^ user .*/) {
$line =~ s/^ user.\s//;
my ($objRootDSE, $strDomain, $strUsername, $objConnection, $objCommand, $objRecordSet, $strDN, $arrSplitResponse, $strLName, $strFName, $strUserType);
use constant ADS_SCOPE_SUBTREE => 2;
# Get domain components
$objRootDSE = Win32::OLE->GetObject('LDAP://RootDSE');
$strDomain = $objRootDSE->Get('DefaultNamingContext');
# Get username to search for
$strUsername = $line;
# Set ADO connection
$objConnection = Win32::OLE->new('ADODB.Connection');
$objConnection->{Provider} = 'ADsDSOObject';
$objConnection->Open('Active Directory Provider');
# Set ADO command
$objCommand = Win32::OLE->new('ADODB.Command');
$objCommand->{ActiveConnection} = $objConnection;
$objCommand->SetProperty("Properties", 'Searchscope', ADS_SCOPE_SUBTREE);
$objCommand->{CommandText} = 'SELECT distinguishedName, userAccountControl, pwdLastSet FROM \'LDAP://' . $strDomain . '\' WHERE objectCategory=\'user\' AND samAccountName = \'' . $strUsername . '\'';
# Set recordset to hold the query result
$objRecordSet = $objCommand->Execute;
# If a user was found - Retrieve the distinguishedName
if (!$objRecordSet->EOF) {
$strDN = $objRecordSet->Fields('distinguishedName')->Value;
$strAcctControl = $objRecordSet->Fields('userAccountControl')->Value;
$strpwdLS = sprintf($objRecordSet->Fields('pwdLastSet')->Value);
#arrSplitResponse = split(/,/, $strDN);
$strLName = substr($arrSplitResponse[0],3);
if ($strLName =~ m/\\$/) {
$strLName = substr($strLName,0,-1);
}
$strFName = $arrSplitResponse[1];
if ($strFName =~ m/OU=/) {
$strUserType = $strFName;
$strFName = "";
$strUserType = substr($strUserType,3);
} else {
$strUserType = substr($arrSplitResponse[2],3);
}
if ($strAcctControl == 512) {
$strAcctControl = "Active";
} else {
$strAcctControl = "Disabled";
}
} else {
print "No user found";
}
&debug("Match!: $line in $group\n");
$csv->print_data(
AccountName => $line,
LastName => $strLName,
FirstName => $strFName,
SYSGenericAcct => $strUserType,
AccessLevel => $group,
AccessCapability => "User",
Description => $desc,
Status => $strAcctControl,
LastPwdChange => $strpwdLS
);
} else {
$group = $line;
chomp($desc = <GROUPS>);
chomp($group2 = <GROUPS>);
&debug("$group\n$desc\n$group\n");
}
}
Use Net::Ldap to search AD server. It is fast and it is portable. It is possible to search AD server from other hosts, even from linux. It is a fast and mature module.
You could also do some debug, using Data::Dumper.
use Data::Dumper;
...
print Dumper($strpwdLS);
I found this thread: http://code.activestate.com/lists/pdk/3876/
# Calculate password age in days
my $PWage;
my $LastPW = $item->{pwdLastSet};
my $fRef = ref ($LastPW);
my ($Hval, $Lval);
if ($fRef eq 'Win32::OLE' )
{
$Hval = $LastPW->HighPart;
$Lval = $LastPW->LowPart;
my $Factor = 10000000; # convert to seconds
my $uPval = pack("II",$Lval,$Hval);
my ($bVp, $aVp) = unpack("LL", $uPval);
$uPval = ($aVp*2**32+$bVp)/$Factor;
if ($uPval != 0)
{
$uPval -= 134774*86400; #Adjust for perl time!
my $EpochSeconds = time;
$PWage = ($EpochSeconds - int($uPval))/(60*60*24) ;
$PWage =~ s/\..*$//;
}
}

how to query eXist using XPath?

I decided to use eXist as a database for an application that I am writing in Perl and
I am experimenting with it. The problem is that I have stored a .xml document with the following structure
<foo-bar00>
<perfdata datum="GigabitEthernet3_0_18">
<cli cmd="whatsup" detail="GigabitEthernet3/0/18" find="" given="">
<input_rate>3</input_rate>
<output_rate>3</output_rate>
</cli>
</perfdata>
<timeline>2011-5-23T11:15:33</timeline>
</foo-bar00>
and it is located in the "/db/LAB/foo-bar00/2011/5/23/11_15_33.xml" collection.
I can successfully query it, like
my $xquery = 'doc("/db/LAB/foo-bar00/2011/5/23/11_15_33.xml")' ;
or $xquery can be equal to
= doc("/db/LAB/foo-bar00/2011/5/23/11_15_33.xml")/foo-bar00/perfdata/cli/data(output_rate)
or
= doc("/db/LAB/foo-bar00/2011/5/23/11_15_33.xml")/foo-bar00/data(timeline)
my ($rc1, $set) = $eXist->executeQuery($xquery) ;
my ($rc2, $count) = $eXist->numberOfResults($set) ;
my ($rc3, #data) = $eXist->retrieveResults($set) ;
$eXist->releaseResultSet($set) ;
print Dumper(#data) ;
And the result is :
$VAR1 = {
'hitCount' => 1,
'foo-bar00' => {
'perfdata' => {
'cli' => {
'given' => '',
'detail' => 'GigabitEthernet3/0/18',
'input_rate' => '3',
'cmd' => 'whatsup',
'output_rate' => '3',
'find' => ''
},
'datum' => 'GigabitEthernet3_0_18'
},
'timeline' => '2011-5-23T11:15:33'
}
};
---> Given that I know the xml document that I want to retrieve info from.
---> Given that I want to retrieve the timeline information.
When I am writing :
my $db_xml_doc = "/db/LAB/foo-bar00/2011/5/23/11_15_33.xml" ;
my ($db_rc, $db_datum) = $eXist->queryXPath("/foo-bar00/timeline", $db_xml_doc, "") ;
print Dumper($db_datum) ;
The result is :
$VAR1 = {
'hash' => 1717362942,
'id' => 3,
'results' => [
{
'node_id' => '1.2',
'document' => '/db/LAB/foo-bar00/2011/5/23/11_15_33.xml'
}
]
};
The question is : How can I retrieve the "timeline" info ? Seems that the "node_id" variable (=1.2) can points to the "timeline" info, but how can I use it ?
Thank you.
use XML::LibXML qw( );
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('a.xml');
my $root = $doc->documentElement();
my ($timeline) = $root->findnodes('timeline');
if ($timeline) {
print("Exists: ", $timeline->textContent(), "\n");
}
or
my ($timeline) = $root->findnodes('timeline/text()');
if ($timeline) {
print("Exists: ", $timeline->getValue(), "\n");
}
I could have used /foo-bar00/timeline instead of timeline, but I didn't see the need.
Don't know if you're still interested, but you could either retrieve the doc as DOM and apply an xquery to the DOM, or, probably better, only pull out the info you want in the query that you submit to the server.
Something like this:
for $p in doc("/db/LAB/foo-bar00/2011/5/23/11_15_33.xml")//output_rate
return
<vlaue>$p</value>