File Coverage

blib/lib/Net/SolarWinds/REST/Batch.pm
Criterion Covered Total %
statement 12 530 2.2
branch 0 196 0.0
condition 0 21 0.0
subroutine 4 21 19.0
pod 17 17 100.0
total 33 785 4.2


line stmt bran cond sub pod time code
1             package Net::SolarWinds::REST::Batch;
2              
3             =head1 NAME
4              
5             Net::SolarWinds::REST::Batch - SolarWinds Batch Process class
6              
7             =head1 SYNOPSIS
8              
9             use strict;
10             use warnings;
11             use Data::Dumper;
12             use Net::SolarWinds::REST::Batch
13              
14             my $self=new Net::SolarWinds::REST::Batch;
15              
16             my $result=$self->get_node('kstlldrmap04');
17              
18             die $result unless $result;
19              
20             print Dumper($result->get_data);
21              
22              
23              
24             =head1 DESCRIPTION
25              
26             A wrapper class for Net::SolarWinds::REST, that provides high level batch like interfaces that tie a lot of the smaller functions togeather.
27              
28             =head1 Extends Net::SolarWinds::REST
29              
30             All of the base funtions provided by Net::SolarWinds::REST are included in this module, for better or worse!
31              
32             =cut
33              
34              
35 1     1   767 use strict;
  1         2  
  1         27  
36 1     1   5 use warnings;
  1         2  
  1         23  
37 1     1   4 use Data::Dumper;
  1         2  
  1         65  
38 1     1   7 use base qw(Net::SolarWinds::REST);
  1         2  
  1         509  
39              
40             =head2 OO Methods
41              
42             This section covers the OO Methods of the class.
43              
44             =over 4
45              
46             =item * my $result=$self->manage_node($struct,$allow_failure);
47              
48              
49             $allow_failure is optional, if not defined it is set to true.
50             The flag allows for the falure of anything other than the node itself not being created.
51              
52             A fairly complex interface used to build out a node for management.
53              
54             Example of the data of $struct:
55              
56             {
57             # list of snmp pollers for the node
58             # see also: add_pollers
59             "node_pollers" => [
60             "N.AssetInventory.Snmp.Generic",
61             "N.Cpu.SNMP.HrProcessorLoad",
62             "N.Details.SNMP.Generic",
63             "N.Memory.SNMP.NetSnmpReal",
64             "N.ResponseTime.ICMP.Native",
65             "N.ResponseTime.SNMP.Native",
66             "N.Status.ICMP.Native",
67             "N.Status.SNMP.Native",
68             "N.Topology_Layer3.SNMP.ipNetToMedia",
69             "N.Uptime.SNMP.Generic"
70             ],
71            
72             # see also: add_volumes
73             "volumes" => ["/home/apm","/tmp","/var"],
74              
75             # The Network Interfaces to monitor
76             # see also: manage_interfaces
77             "interfaces"=>["eth0","eth1","eth2"],
78              
79             "custom_properties"=>{
80             "dcinstance" => "production",
81             "administrator" => "EMS/NMS",
82             },
83            
84             # denote if this node needs to be replaced as it is created
85             # see also, build_node
86             "replace" => false,
87              
88             # The disk volumes to monitor
89             # Argumetns required to build a node
90             # see also, build_node
91             "node" => {
92             "EngineID" => 18,
93             "Status" => 1,
94             "IPAddress" => "192.168.101.38",
95             "RediscoveryInterval" => 30,
96             "Community" => "public",
97             "DisplayName" => "kstlldrmap04",
98             "MachineType" => "net-snmp - Linux",
99             "UnManaged" => false,
100             "PollInterval" => 46,
101             "StatCollection" => 10,
102             "SysObjectID" => "1.3.6.1.4.1.8072.3.2.10",
103             "SNMPVersion" => 2,
104             "DynamicIP" => false,
105             "Caption" => "kstlldrmap04",
106             "ObjectSubType" => "SNMP",
107             "VendorIcon" => "8072.gif ",
108             "Allow64BitCounters" => true
109             },
110              
111             # Note: This requires the APM module in Solarwinds
112             # denote objects used to create templates
113             # see also: add_templates
114             "templates" => [
115             "SDS - Application details-U/L - Warning",
116             "SDS - DMS Adaptor Daemon Monitor - Critical",
117             "SDS - Drum - Warning",
118             "AWS Mail Alert Daemon",
119             "CPM Ghosting"
120             ]
121             }
122              
123             =cut
124              
125             sub manage_node {
126 0     0 1   my ($self,$info,$allow_failure)=@_;
127 0 0         $allow_failure=1 unless defined($allow_failure);
128            
129 0           $self->log_info("starting with $info->{node}->{IPAddress} replace: $info->{replace}");
130              
131 0           my $data={};
132              
133 0           my $result=$self->build_node($info->{node}->{IPAddress},$info->{replace},%{$info->{node}});
  0            
134 0 0         unless($result) {
135 0           my $msg="build_node $info->{node}->{IPAddress},$info->{replace} failed error was: $result";
136 0           $self->log_error($msg);
137 0           $self->log_info("stopping");
138 0           return $self->RESULT_CLASS->new_false($msg);
139             }
140 0           $data->{node}=$result->get_data;
141 0           my $node_id=$result->get_data->{NodeID};
142              
143              
144 0 0         if(exists $info->{interfaces}) {
145 0           $result=$self->manage_interfaces($node_id,@{$info->{interfaces}});
  0            
146 0 0         unless($result) {
147 0           my $msg="Failed durring interfaces update error was: ".$result;
148 0           $self->log_error($msg);
149 0           $self->log_info("stopping");
150 0 0         return $self->RESULT_CLASS->new_false($msg) unless $allow_failure;
151             }
152 0           $data->{interfaces}=$result->get_data;
153             }
154              
155              
156 0 0         if(exists $info->{custom_properties}) {
157 0           $result=$self->NodeCustomProperties($node_id,$info->{custom_properties});
158 0 0         unless($result) {
159 0           my $msg="Failed durring custom properties update error was: ".$result;
160 0           $self->log_error($msg);
161 0           $self->log_info("stopping");
162 0 0         return $self->RESULT_CLASS->new_false($msg) unless $allow_failure;
163             }
164 0           $data->{custom_properties}=$result->get_data;
165             }
166              
167 0 0         if(exists $info->{node_pollers}) {
168 0           $result=$self->add_pollers($node_id,'N',@{$info->{node_pollers}});
  0            
169 0 0         unless($result) {
170 0           my $msg="Failed durring node pollers update error was: ".$result;
171 0           $self->log_error($msg);
172 0           $self->log_info("stopping");
173 0 0         return $self->RESULT_CLASS->new_false($msg) unless $allow_failure;
174             }
175 0           $data->{node_pollers}=$result->get_data;
176             }
177              
178 0 0         if(exists $info->{volumes}) {
179 0           $result=$self->add_volumes($node_id,@{$info->{volumes}});
  0            
180 0 0         unless($result) {
181 0           my $msg="Failed durring volumes update error was: ".$result;
182 0           $self->log_error($msg);
183 0           $self->log_info("stopping");
184 0 0         return $self->RESULT_CLASS->new_false($msg) unless $allow_failure;
185             }
186 0           $data->{volumes}=$result->get_data;
187             }
188              
189 0 0         if(exists $info->{templates}) {
190 0           $result=$self->add_templates($node_id,@{$info->{templates}});
  0            
191 0 0         unless($result) {
192 0           my $msg="Failed durring templates update error was: ".$result;
193 0           $self->log_error($msg);
194 0           $self->log_info("stopping");
195 0 0         return $self->RESULT_CLASS->new_false($msg) unless $allow_failure;
196             }
197 0           $data->{templates}=$result->get_data;
198             }
199              
200 0           $self->log_info("stopping");
201 0           return $self->RESULT_CLASS->new_true($data);
202             }
203              
204             =item * my $result=$self->get_node($thing);
205              
206             $thing can contain any one of the following: NodeID, IpAddress, Caption.
207              
208             This method returns a Net::SolarWinds::Result object.
209              
210             When true it contains the first node found that matched what was passed in as $thing.
211              
212             When false it contains why it failed.
213              
214             =cut
215              
216             sub get_node {
217 0     0 1   my ($self,$id)=@_;
218              
219 0           $self->log_info("starting id: $id");
220 0           my $result;
221             my $lookup;
222 0 0         if($id=~ /^\d+$/) {
    0          
223 0           $result=$self->getNodesByID($id);
224 0           $lookup="id";
225             } elsif($id=~ /\d\.\d/) {
226 0           $result=$self->getNodesByIp($id);
227 0           $lookup="ip";
228             } else {
229 0           $result=$self->getNodesByDisplayName($id);
230 0           $lookup="hostname";
231             }
232              
233 0 0         unless($result) {
234 0           $self->log_error($result);
235 0           $self->log_info("stopping");
236 0           return $result ;
237             }
238 0           my $list=$result->get_data->{results};
239              
240 0 0         if($#{$list}==-1) {
  0            
241 0           my $msg="Node $id not found by $lookup";
242 0           $self->log_debug(Dumper($result));
243 0           $self->log_error($msg);
244 0           $self->log_info("stopping");
245 0           return $self->RESULT_CLASS->new_false($msg);
246             }
247 0           $self->log_info("stopping");
248 0           return $self->RESULT_CLASS->new_true($list->[0]);
249             }
250              
251             =item * my $result=$self->set_managed($thing,0|1);
252              
253             This is really just a wrapper for $self->get_node followed by $self->UpdateNodeProps($node_id,UnManaged=>0|1);
254              
255             Returns a Net::SolarWinds::Result object
256              
257             =cut
258              
259             sub set_managed {
260 0     0 1   my ($self,$ip,$state)=@_;
261 0 0         $state=0 unless defined($state);
262              
263 0           my $result=$self->get_node($ip);
264 0 0         return $result unless $result;
265 0           my $node=$result->get_data;
266 0           my $node_id=$node->{NodeID};
267              
268 0           return $self->UpdateNodeProps($node_id,UnManaged=>&JSON::true);
269             }
270              
271             =item * my $result=$self->get_management_config($thing);
272              
273             Programatic way build a refrence template for: manage_node
274              
275             Returns a Net::SolarWinds::Result object
276             If true, it contains a data structure requried to build out the node refred to as $thing.
277             If false, it contains why it failed.
278              
279             =cut
280              
281             sub get_management_config {
282 0     0 1   my ($self,$ip)=@_;
283              
284 0           my $result=$self->get_node($ip);
285 0 0         return $result unless $result;
286              
287 0           my $node=$result->get_data;
288 0           my $node_id=$node->{NodeID};
289 0           delete $node->{NodeID};
290 0           delete $node->{Uri};
291 0           delete $node->{EntityType};
292 0           delete $node->{IPAddressGUID};
293              
294 0           $result=$self->get_poller_map($node_id,'N');
295 0 0         return $result unless $result;
296             my $node_pollers=[
297             sort
298 0           keys %{ $result->get_data->{"N:$node_id"} }
  0            
299             ];
300              
301 0           $result=$self->getInterfacesOnNode($node_id);
302 0 0         return $result unless $result;
303             my $interfaces=[
304             sort
305             map {
306 0           my $int_id=$result->get_data->{$_}->{InterfaceID};
307 0           my $res=$self->NodeInterfaceCustomProperties($node_id,$int_id);
308 0 0         my $custom_props=$res ? $res->get_data : {};
309              
310             # clean up any properties that are not set
311 0           delete $custom_props->{InterfaceID};
312 0           delete $custom_props->{InstanceType};
313 0           while (my ($key,$value)=each %{$custom_props}) {
  0            
314 0 0         delete $custom_props->{$key} unless defined($value);
315             }
316              
317 0           $res=$self->get_poller_map($int_id,'I');
318 0 0         my $pollers=$res ? [ sort keys %{$res->get_data->{"I:$int_id"}}] : [];
  0            
319             {
320 0           ifname=>$_,
321             custom_props=>$custom_props,
322             pollers=>$pollers,
323             }
324             }
325 0           keys %{ $result->get_data }
  0            
326             ];
327              
328 0           $result=$self->getVolumeMap($node_id);
329 0 0         return $result unless $result;
330             my $volumes=[
331             map {
332 0           my $vol_id=$_->{VolumeID};
333 0           my $res=$self->get_poller_map($vol_id,'V');
334 0 0         my $pollers=$res ? [ sort keys %{$res->get_data->{"V:$vol_id"}}] : [];
  0            
335             {
336             path=>$_->{Caption},
337             type=>$_->{Type},
338 0           pollers=>$pollers,
339             }
340 0           } values %{ $result->get_data->{'map'} }
  0            
341             ];
342              
343 0           $result=$self->NodeCustomProperties($node_id);
344 0 0         return $result unless $result;
345              
346 0           my $custom_props=$result->get_data;
347 0           delete $custom_props->{NodeID};
348 0           delete $custom_props->{InstanceType};
349 0           while(my ($key,$value)=each %{$custom_props}) {
  0            
350 0 0         delete $custom_props->{$key} unless defined($value);
351             }
352              
353 0           $result=$self->getTemplatesOnNode($node_id);
354 0 0         return $result unless $result;
355              
356 0           my $templates=[];
357 0           foreach my $tmpl (@{$result->get_data}) {
  0            
358 0           push @{$templates},$tmpl->{Name};
  0            
359             }
360 0           my $config={
361             node=>$node,
362             node_pollers=>$node_pollers,
363             interfaces=>$interfaces,
364             volumes=>$volumes,
365             custom_properties=>$custom_props,
366             templates=>$templates,
367             };
368              
369 0           $config->{replace}=&JSON::false;
370 0           return $self->RESULT_CLASS->new_true($config);
371             }
372              
373             =item * my $result=$self->get_poller_map($id,$type);
374              
375             Used to get a uniqe hash of all pollers assigned to this object.
376              
377             $id can be:
378             NodeID $type=N
379             VolumeID $type=V
380             InterfaceID $type=I
381              
382             Returns a Net::SolarWinds::Result object.
383              
384             =cut
385              
386             sub get_poller_map {
387 0     0 1   my ($self,$node_id,$type)=@_;
388              
389 0 0         $type='N' unless defined($type);
390 0           $self->log_info("starting node_id: $node_id type: $type");
391 0           my $query=$self->query_lookup($node_id,$type);
392 0           my $result=$self->Query($query);
393 0 0         unless($result) {
394 0           $self->log_error("query failed error was: $result");
395 0           $self->log_info("stopping");
396 0           return $result;
397             }
398              
399 0           my $map={};
400              
401 0           my $list=$result->get_data->{results};
402              
403 0           foreach my $poller (@{$list}) {
  0            
404 0           my $id=$poller->{NetObjectID};
405 0 0 0       next if defined $type and $type ne $poller->{NetObjectType};
406 0           $map->{$poller->{NetObject}}->{$poller->{PollerType}}=$poller;
407             }
408              
409 0           $self->log_info("stopping");
410 0           return $self->RESULT_CLASS->new_true($map);
411             }
412              
413             =item * my $result=$self->getPollerInterfaceMap($nodeid)
414              
415             Returns a Net::SolarWinds::Result object, when true it contains a hash mapping ifType to PollerType
416              
417             =cut
418              
419             sub getPollerInterfaceMap {
420 0     0 1   my ($self,$nodeid)=@_;
421              
422 0           $self->log_info("Starting poller type lookup of nodeid: $nodeid");
423 0           my $query=$self->query_lookup($nodeid);
424              
425 0           my $result=$self->Query($query);
426 0 0         unless($result) {
427 0           $self->log_error("Finished poller type lookup of nodeid: $nodeid error was: $result");
428 0           return $result;
429             }
430              
431 0           my $hash={};
432 0           my $list=$result->get_data->{results};
433              
434 0           foreach my $poller (@{$list}) {
  0            
435 0           my $id=$poller->{ifType};
436 0 0         $hash->{$id}=[] unless exists $hash->{$id};
437 0           push @{$hash->{$id}},$poller->{PollerType};
  0            
438             }
439              
440 0           $self->log_info("Finished poller type lookup of nodeid: $nodeid");
441 0           return $self->RESULT_CLASS->new_true($hash);
442             }
443              
444             =item * my $result=$self->GetNodeInterfacePollers($nodeid)
445              
446             When true it returns a Net::SolarWinds::Result object that contains the interface poller and id info.
447              
448             =cut
449              
450             sub GetNodeInterfacePollers {
451 0     0 1   my ($self,$nodeid)=@_;
452 0           my $query=$self->query_lookup($nodeid);
453 0           my $result=$self->Query($query);
454 0           return $result;
455             }
456              
457             =item * my $result=$self->add_pollers($id,$t,@pollers);
458              
459             Adds a list of pollers of type to given id.
460              
461             $id can be:
462             NodeID $type=N
463             VolumeID $type=V
464             InterfaceID $type=I
465              
466             @polers contains a list of snmp pollers.
467              
468             Example:
469              
470             "N.Details.SNMP.Generic",
471             "N.ResponseTime.ICMP.Native",
472             "N.ResponseTime.SNMP.Native",
473             "N.Status.ICMP.Native",
474             "N.Status.SNMP.Native",
475             "N.Uptime.SNMP.Generic"
476              
477             Returns a Net::SolarWinds::Result Object.
478              
479             =cut
480              
481             sub add_pollers {
482 0     0 1   my ($self,$node_id,$t,@pollers)=@_;
483              
484 0           $self->log_info("Starting object_id: $node_id type: $t pollers: ".join ', ',@pollers);
485              
486 0           my $result=$self->get_poller_map($node_id,$t);
487 0 0         unless($result) {
488 0           $self->log_error("failed to get_poller_map error was: $result");
489 0           $self->log_info("stopping");
490 0           return $result;
491             }
492 0           my $id=$t.':'.$node_id;
493              
494 0           my $map=$result->get_data;
495              
496 0           my $pollers=[];
497 0           foreach my $poller (@pollers) {
498             # skip duplicate pollers
499 0 0         if(exists $map->{$id}->{$poller}) {
500 0           $self->log_warn("poller $poller exists on object $node_id skipping!");
501             next
502 0           }
503 0           my $result=$self->add_poller($node_id,$t,$poller);
504 0 0         unless($result) {
505 0           $self->log_error("Faield to add poller for object_id $node_id type: $t poller: $poller error was $result");
506 0           $self->log_info("stopping");
507 0           return $result;
508             }
509 0           push @{$pollers},$result->get_data;
  0            
510             }
511              
512 0           $self->log_info("stopping");
513 0           return $self->RESULT_CLASS->new_true($pollers);
514             }
515              
516             =item * my $result=$self->add_volumes($node_id,@vols);
517              
518             $node_id is the NodeID of the device
519              
520             @vols can contain a mix of [either list of objects or volume names.
521              
522             Object Example:
523              
524             {
525             "pollers" => [
526             "V.Details.SNMP.Generic",
527             "V.Statistics.SNMP.Generic",
528             "V.Status.SNMP.Generic"
529             ],
530             "type" => "Network Disk",
531             "path" => "/home/apm"
532             },
533              
534             String Example:
535              
536             '/var'
537              
538             When using the string example, the default pollers are added.
539              
540             =cut
541              
542             sub add_volumes {
543 0     0 1   my ($self,$node_id,@vols)=@_;
544              
545 0           $self->log_info("starting node_id: $node_id");
546 0           my $result=$self->getVolumeTypeMap;
547 0 0         unless($result) {
548 0           $self->log_error("Failed to get getVolumeTypeMap error was: $result");
549 0           $self->log_info("stopping");
550 0           return $result;
551             }
552              
553 0           my $map=$result->get_data;
554              
555 0           $result=$self->getVolumeMap($node_id);
556 0 0         unless($result) {
557 0           $self->log_error("Failed to get getVolumeMap error was: $result");
558 0           $self->log_info("stopping");
559 0           return $result;
560             }
561              
562 0           my $vol_map=$result->get_data->{'map'};
563 0           my $MaxVolumeIndex=$result->get_data->{MaxVolumeIndex};
564              
565 0           my $added={};
566 0           PROV_LOOP: foreach my $vol (@vols) {
567             # force the object to a hash ref..
568 0 0 0       $vol={path=>$vol}
569             unless ref($vol) and ref($vol) eq 'HASH';
570 0           my $path=$vol->{path};
571 0           my $obj;
572 0 0         if(exists $vol_map->{$path}) {
573 0           $self->log_warn("volume in monitoring all ready, will not re-add: $path");
574 0           $obj=$vol_map->{$path};
575             } else {
576 0           ++$MaxVolumeIndex;
577 0           $self->log_warn("volume does not exist we will create: $path");
578             #%{ $map->{$vol->{type}}},
579              
580 0           my %args=(
581             Caption=>$path,
582             VolumeDescription=>$path,
583             NodeID=>$node_id,
584             VolumeIndex=>$MaxVolumeIndex,
585             );
586              
587 0           $self->log_always("Adding volume with options: ",Dumper(\%args));
588 0           $result=$self->add_volume(%args);
589 0 0         unless($result) {
590 0           $self->log_warn("failed to add volume $path error was: $result");
591 0           next PROV_LOOP;
592             }
593              
594 0           my $url=$result->get_data;
595 0           $url=~ s/(?:^"|"$)//g;
596 0           my ($VolumeID)=$url=~ /(\d+)$/;
597 0           $args{VolumeID}=$VolumeID;
598 0           $obj={%args};
599 0           $added->{$path}->{obj}=$obj;
600             }
601              
602 0 0 0       if(exists $vol->{pollers} and ref($vol->{pollers}) eq 'ARRAY') {
603 0           my $pollers=$vol->{pollers};
604 0           my $volume_id=$obj->{VolumeID};
605 0           my $result=$self->add_pollers($volume_id,'V',@{$pollers});
  0            
606 0 0         if($result) {
607 0           $added->{$path}->{pollers}=$result->get_data;
608             } else {
609 0           $self->log_error("failed to add pollers to volume: $volume_id error was: $result");
610 0           $self->log_info("stopping");
611 0           $added->{$path}->{pollers}={ERROR=>"$result"};
612             }
613             }
614             }
615              
616 0           $self->log_info("stopping");
617 0           return $self->RESULT_CLASS->new_true($added);
618             }
619              
620             =item * my $result=$self->add_templates($node_id,@templates);
621              
622             Add a list of templates to the device for monitoring.
623              
624             $$node_id is the NodeID of the node
625              
626             @templates Example list:
627              
628             "SDS - Application details-U/L - Warning",
629             "SDS - DMS Adaptor Daemon Monitor - Critical",
630             "SDS - Drum - Warning",
631             "AWS Mail Alert Daemon",
632             "CPM Ghosting"
633              
634             =cut
635              
636             sub add_templates {
637 0     0 1   my ($self,$node_id,@templates)=@_;
638              
639 0           my $list=[];
640 0 0         if(@templates) {
641 0           my $result=$self->getApplicationTemplate(@templates);
642 0 0         return $result unless $result;
643 0           $list=$result->get_data->{results};
644             }
645              
646 0           my $tmpls=[];
647 0           foreach my $tmpl (@{$list}) {
  0            
648 0           my $id=$tmpl->{ApplicationTemplateID};
649 0           my $result=$self->addTemplateToNode($node_id,$id);
650 0 0         next unless $result;
651 0           push @{$tmpls},$result->get_data;
  0            
652             }
653              
654 0           return $self->RESULT_CLASS->new_true($tmpls);
655             }
656              
657             =item * my $result=$self->manage_interfaces($node_id,@interfaces);
658              
659             $node_id is the "NodeID" of the machine to work with
660              
661             @interfaces contains a list of Object hashes or interface names.
662              
663             Object Example: In the object example all details, such as the pooler and custom properties are set manually.
664              
665             {
666             "pollers" : [
667             "I.Rediscovery.SNMP.IfTable",
668             "I.StatisticsErrors32.SNMP.IfTable",
669             "I.StatisticsTraffic.SNMP.Universal",
670             "I.Status.SNMP.IfTable"
671             ],
672             "ifname" : "eth1",
673             "custom_props" : {
674             "alert_rx_percent_utilization" : 90,
675             "alarmerrorrate" : 0,
676             "alert_tx_percent_utilization" : 90
677             }
678             }
679              
680             Interface name example: In the interface name example just the name of the interface is passed.
681              
682             'eth0'
683              
684              
685             Odds are you will just want to use a list of human readable interface names:
686              
687             "eth0","eth1","eth2"
688              
689             Notes:
690              
691             Gives up at the first error, and may not complete the process of adding things. Odds are this code will need to be made more forgiving.
692              
693             =cut
694              
695             sub manage_interfaces {
696 0     0 1   my ($self,$node_id,@interfaces)=@_;
697 0           $self->log_info("starting node_id: $node_id");
698              
699 0           my $result=$self->DiscoverInterfaceMap($node_id);
700 0 0         unless($result) {
701 0           $self->log_error("failed to discover interfaces on node_id: $node_id error was: $result");
702 0           $self->log_info("stopping");
703 0           return $result;
704             }
705              
706 0           my $map=$result->get_data;
707 0           $self->log_debug("Interfaces: ".Dumper($map));
708            
709 0           my $add_poller=[];
710 0           my $no_add_poller=[];
711 0           my $add_pollers=[];
712 0           my $add_pollers_to={};
713 0           my $set_props={};
714              
715 0           foreach my $obj (@interfaces) {
716 0           my ($int,$ref);
717              
718 0 0         if(ref($obj) eq 'HASH') {
719 0           $int=$obj->{ifname};
720 0 0         unless(exists $map->{$int}) {
721 0           $self->log_warn("ifname $int was not found in the discovery table!");
722 0           next;
723             }
724 0           $ref=$map->{$int};
725             $set_props->{$int}=$obj
726             if exists $obj->{custom_props}
727             and ref($obj->{custom_props}) eq 'HASH'
728 0 0 0       and keys(%{$obj->{custom_props}})!=0;
  0   0        
729 0 0 0       if(exists $obj->{pollers} and ref($obj->{pollers}) eq 'ARRAY') {
    0          
730            
731 0 0         if($#{$obj->{pollers}}!=-1) {
  0            
732             # use explicit pollers
733 0           push @{$add_pollers},$int;
  0            
734 0           $add_pollers_to->{$int}=$obj;
735 0 0         if($ref->{InterfaceID}!=0) {
736 0           $self->log_warn("ifname $int is all ready managed");
737 0           next;
738             }
739 0           $self->log_info("ifname $int exists does not yet have an id we will addd it with custom properties!");
740 0           push @{$no_add_poller},$ref;
  0            
741             } else {
742             # only set default polelrs if the list is empty
743 0 0         if($ref->{InterfaceID}!=0) {
744 0           $self->log_warn("ifname $int is all ready managed");
745 0           next;
746             }
747 0           $self->log_info("ifname $int exists does not yet have an id we will addd it to default pollers");
748 0           push @{$add_poller},$ref;
  0            
749             }
750             } elsif($ref->{InterfaceID}!=0) {
751 0           push @{$add_poller},$ref;
  0            
752             }
753            
754             } else {
755 0           $int=$obj;
756 0 0         unless(exists $map->{$int}) {
757 0           $self->log_warn("ifname $int was not found in the discovery table!");
758 0           next;
759             }
760 0           $ref=$map->{$int};
761 0 0         next if $ref->{InterfaceID}!=0;
762 0           $self->log_info("ifname $int exists does not yet have an id we will addd it to default pollers");
763 0           push @{$add_poller},$ref;
  0            
764             }
765             }
766 0           my $data=[];
767 0 0         if($#{$add_poller} > -1) {
  0            
768 0           $result=$self->NodeInterfaceAddDefaultPollers($node_id,$add_poller);
769 0 0         return $result unless $result;
770 0           foreach my $obj (@{$result->get_data->{DiscoveredInterfaces}}) {
  0            
771 0           foreach my $int ($self->InterfaceCaptionTranslation($obj->{Caption})) {
772 0           push @{$data},$int;
  0            
773             }
774             }
775             }
776            
777 0 0         if($#{$no_add_poller} > -1) {
  0            
778 0           $result=$self->NodeAddInterface($node_id,$no_add_poller);
779 0 0         return $result unless $result;
780 0           my $tmap=$self->build_interface_result_map($result)->get_data;
781 0           %{$map}=(
782 0           %{$map},
783 0           %{$tmap}
  0            
784             );
785 0           foreach my $int (@{$add_pollers}) {
  0            
786 0 0         next unless exists $map->{$int};
787 0           my $obj=$add_pollers_to->{$int};
788 0           my $id=$map->{$int}->{InterfaceID};
789 0           my $result=$self->add_pollers($id,'I',@{$obj->{pollers}});
  0            
790 0 0         return $result unless $result;
791 0           push @{$data},$obj;
  0            
792             }
793             }
794              
795 0           while (my ($int,$ref)=each %{$set_props}) {
  0            
796 0 0         next unless exists $map->{$int};
797 0           my $result=$self->NodeInterfaceCustomProperties($node_id,$map->{$int}->{InterfaceID},$ref->{custom_props});
798 0 0         return $result unless $result;
799             }
800 0           $self->log_info("stopping");
801 0           return $self->RESULT_CLASS->new_true($data);
802             }
803              
804             =item * my $result=$self->create_or_update_node($ip,%args);
805              
806             Wrapper for $self->build_node with $DeleteIfExists set to false
807              
808             =cut
809              
810             sub create_or_update_node {
811 0     0 1   my ($self,$ip,%args)=@_;
812 0           return $self->build_node($ip,0,%args);
813             }
814              
815             =item * my $result=$self->replace_node($ip,%args);
816              
817             Wrapper for $self->build_node with $DeleteIfExists set to true
818              
819             =cut
820              
821             sub replace_node {
822 0     0 1   my ($self,$ip,%args)=@_;
823 0           return $self->build_node($ip,1,%args);
824             }
825              
826             =item * my $result=$self->build_node($ip,$DeleteIfExists,%args);
827              
828             Used to create a node if it does not exist.
829              
830             Variabels:
831             $ip
832             The ipv4 address of the box
833              
834             $DeleteIfExists
835             if this value is set to true and this node exists all ready
836             it will be deleted and re-created!
837              
838             %args
839             The node properties
840             See also: Net::SolarWinds::REST::UpdateNodeProps
841              
842             =cut
843              
844             sub build_node {
845 0     0 1   my ($self,$ip,$DeleteIfExists,%args)=@_;
846              
847 0           $self->log_info("Starting lookup of $ip");
848 0           my $nodeID;
849 0           my $result=$self->get_node($ip);
850 0 0         $args{IPAddress}=$ip unless exists $args{IPAddress};
851            
852            
853 0 0         if($result) {
854 0           $nodeID=$result->get_data->{NodeID};
855 0           $self->log_info("Node exists: NodeID is $nodeID");
856 0 0         if($DeleteIfExists) {
857 0           $self->log_info("Node exists we were called in replace mode");
858 0           my $result=$self->deleteNode($nodeID);
859 0 0         unless($result) {
860 0           $self->log_error("Failed to delete NodeID: $nodeID");
861 0           $self->log_info("stopping");
862 0           return $result;
863             }
864 0           $nodeID=undef;
865             } else {
866 0           $self->log_info("Node exists and we were called in update mode");
867 0           $result=$self->UpdateNodeProps($nodeID);
868 0 0         unless($result) {
869 0           $self->log_error("Failed to fetch node propeties for NodeID: $nodeID");
870 0           $self->log_info("stopping");
871 0           return $result;
872             }
873 0           my $existing=$result->get_data;
874 0           my $update=0;
875 0           UPDATE_CHECK: while(my ($key,$value)=each %args) {
876             # work around, we don't want to update node status!
877 0 0         next UPDATE_CHECK if $key eq 'Status';
878              
879             # work around, we don't want to do an eq against numbers
880 0           my $cmp="$value";
881 0 0 0       if(exists $existing->{$key} and defined($existing->{$key})) {
882             # work around, we don't want to do an eq against numbers
883 0           my $current=''.$existing->{$key};
884              
885             # work around cpm returns some space padded values
886 0           $current=~ s/(?:^\s+|\s+$)//g;
887 0           $cmp=~ s/(?:^\s+|\s+$)//g;
888              
889 0 0         if($cmp ne $current) {
890 0           $update=1;
891 0           $self->log_warn("Values do not match [$cmp] ne [$value] on node will need to update");
892 0           last UPDATE_CHECK;
893             }
894             } else {
895 0           $update=1;
896 0           $self->log_warn("Value on node s incorrect will need to update");
897 0           last UPDATE_CHECK;
898             }
899             }
900              
901 0 0         if($update) {
902 0           $result=$self->UpdateNodeProps($nodeID,%args);
903 0 0         unless($result) {
904 0           $self->log_error("Failed to update NodeID: $nodeID");
905 0           $self->log_info("stopping");
906 0           return $result;
907             }
908             }
909             }
910             }
911              
912 0 0         unless($nodeID) {
913 0           $self->log_info("Creating node $ip");
914 0           my $result=$self->createNode(%args);
915 0 0         $self->log_error("Failed to create node: $ip error was: $result") unless($result);
916 0           $self->log_info("stopping");
917 0           return $result;
918             }
919              
920 0           $self->log_info("stopping");
921 0           return $self->RESULT_CLASS->new_true({NodeID=>$nodeID});
922              
923             }
924              
925             =item * my $result=$self->build_unmanaged($ip,$DeleteIfExists,%args);
926              
927             Wrapper for build_node, flips the node to UnManaged=>1 once it has been created or if it all ready exists.
928              
929             =cut
930              
931             sub build_unmanaged {
932 0     0 1   my ($self,$ip,$DeleteIfExists,%args)=@_;
933              
934 0           $self->log_info("Starting build_unmanaged");
935 0           my $result=$self->build_node($ip,$DeleteIfExists,%args);
936 0 0         return $result unless $result;
937              
938 0           my $nodeID=$result->get_data->{NodeID};
939 0           my $target=$result;
940              
941 0           $result=$self->NodeUnmanage($nodeID);
942              
943 0           $self->log_info("Finished build_unmanaged");
944 0 0         return $result unless $result;
945              
946 0           return $target;
947             }
948              
949             =item * my $result=$self->GetAlertSettingsMap($thing);
950              
951             When true, returns a data structure that represents alerting thresholds and custom properties for the node, and its interfaces, templates, and volumes.
952             when fals: returns why it failed
953              
954             $thing can be a nodeid, hostname or ipaddress.
955              
956             =cut
957              
958             sub GetAlertSettingsMap {
959 0     0 1   my ($self,$thing)=@_;
960 0           $self->log_info("Starting $thing");
961 0           my $nodeid;
962 0           my $result=$self->get_node($thing);
963 0           my $node;
964 0 0         if($result) {
965 0           $nodeid=$result->get_data->{NodeID};
966 0           $node=$result->get_data;
967             } else {
968 0           $self->log_info("Failed $thing");
969 0           return $result;
970             }
971 0           my $caption=$result->get_data->{Caption};
972 0           my $map={};
973 0           foreach my $method ('GetAlertSettings','getVolumeMap','getInterfacesOnNode') {
974 0           my $result=$self->$method($nodeid);
975              
976 0 0         unless($result) {
977 0           $self->log_info("Failed $thing");
978 0           return $result;
979             }
980 0           $map->{$method}=$result->get_data;
981 0 0         if(ref($map->{$method}) eq 'ARRAY') {
    0          
    0          
982             # honnestly.. we do nothing
983             } elsif(exists $map->{$method}->{map}) {
984 0           $map->{$method}=$map->{$method}->{map};
985             }elsif(exists $map->{$method}->{results}) {
986 0           $map->{$method}=$map->{$method}->{results};
987             }
988             }
989 0           my $node_settings=[];
990              
991             # used to just map what keys we want in our data set
992 0           foreach my $ref (@{$map->{GetAlertSettings}}) {
  0            
993 0 0         next if $caption ne $ref->{InstanceCaption};
994 0           my $row={};
995 0           push @{$node_settings},$ref
  0            
996             }
997 0           my $alertsettings=$map->{GetAlertSettings};
998 0           delete $map->{GetAlertSettings};
999              
1000              
1001             # walk our template objects
1002 0           $result=$self->getTemplatesOnNode($nodeid);
1003 0           my $tmpls=[];
1004 0           my $tree={Templates=>$tmpls,Caption=>$caption,NodeID=>$nodeid,NodeAlertSettings=>$node_settings};
1005 0 0         unless($result) {
1006 0           $self->log_error("Faield to \$self->getTemplatesOnNode($nodeid)");
1007 0           return $result;
1008             }
1009              
1010 0           foreach my $tmpl (@{$result->get_data}) {
  0            
1011 0           my $obj={Caption=>$tmpl->{Name}};
1012 0           my $uri=$tmpl->{Uri}.'/CustomProperties';
1013 0           my $result=$self->getSwisProps($uri);
1014 0 0         unless($result) {
1015 0           $self->log_error("Faield fetching Application: $obj->{Caption} Custom Properties");
1016 0           return $result;
1017             }
1018 0           $obj->{CustomProperties}=$result->get_data;
1019 0 0         $obj->{CustomProperties}->{Uri}=$uri unless defined($obj->{CustomProperties}->{Uri});
1020 0           push @{$tmpls},$obj;
  0            
1021              
1022             }
1023              
1024 0           my %rename=(qw(
1025             getVolumeMap Volumes
1026             getInterfacesOnNode Interfaces
1027             ));
1028              
1029 0           while(my ($method,$ref) =each %{$map}) {
  0            
1030 0           my $key=$rename{$method};
1031 0           while(my ($name,$obj)=each %{$ref}) {
  0            
1032 0 0         $tree->{$key}=[] unless exists $tree->{$key};
1033              
1034 0           my $sets=$tree->{$key};
1035              
1036 0           my $list=[];
1037 0           my $set={Caption=>$name,Uri=>$obj->{Uri},AlertSettings=>$list};
1038 0           foreach my $setting (@{$alertsettings}) {
  0            
1039 0 0         next if $name ne $setting->{InstanceCaption};
1040              
1041 0           push @{$list},$setting;
  0            
1042             }
1043 0           my $result=$self->getSwisProps($obj->{Uri}.'/CustomProperties');
1044 0 0         unless($result) {
1045 0           $self->log_error("Faield fetching $thing");
1046 0           return $result;
1047             }
1048 0           my $copy={};
1049 0           while(my ($key,$value)=each %{$result->get_data}) {
  0            
1050             #next unless defined($value);
1051 0           $copy->{$key}=$value;
1052             }
1053 0           $set->{CustomProperties}=$copy;
1054 0           push @{$sets},$set;
  0            
1055             }
1056             }
1057 0           $result=$self->NodeCustomProperties($nodeid);
1058 0 0         unless($result) {
1059 0           $self->log_error("Failed $thing");
1060 0           return $result;
1061             }
1062 0           my $custom={};
1063 0           $tree->{NodeCustomProperties}=$custom;
1064 0           while(my ($key,$value)= each %{$result->get_data}) {
  0            
1065             #next unless defined($value);
1066 0           $custom->{$key}=$value;
1067             }
1068            
1069 0           $tree->{NodeDetails}=$node;
1070 0           $self->log_info("Finsihed $thing");
1071 0           return $self->RESULT_CLASS->new_true($tree);
1072             }
1073              
1074             =item * my $result=$self->bulk_ip_lookup(@ip_list)
1075              
1076             Returns a SolarWinds::Result Object.
1077              
1078             When true it contains the search results of all the ips that were looked up
1079              
1080             =cut
1081              
1082             sub bulk_ip_lookup {
1083 0     0 1   my ($self,@ips)=@_;
1084 0           my $join=join "','",@ips;
1085 0           my $query=$self->query_lookup($join);
1086 0           my $result=$self->Query($query);
1087 0           return $result;
1088             }
1089              
1090              
1091             =back
1092              
1093             =head1 AUTHOR
1094              
1095             Michael Shipper
1096              
1097             =cut
1098              
1099             1;
1100              
1101             __END__