File Coverage

blib/lib/Net/SolarWinds/REST.pm
Criterion Covered Total %
statement 94 476 19.7
branch 3 74 4.0
condition 0 3 0.0
subroutine 27 69 39.1
pod 43 46 93.4
total 167 668 25.0


line stmt bran cond sub pod time code
1             package Net::SolarWinds::REST;
2              
3             =head1 NAME
4              
5             Net::SolarWinds::REST - SolarWinds Rest interface
6              
7             =head1 SYNOPSIS
8              
9             use strict;
10             use warnings;
11             use Net::SolarWinds::REST;
12             use Data::Dumper;
13              
14             my $rest=new Net::SolarWinds::REST();
15              
16             my $result=$rest->DiscoverInterfacesOnNode(444);
17              
18             if($result) {
19             print Dumper($result->get_data);
20             } else {
21             print $result,"\n";
22             }
23              
24             =head1 DESCRIPTION
25              
26             Anyone who has used SOAP::Lite to try to interface with solarwinds knows how difficult and frustrating it can be. This collection of modules provides a restful interface to SolarWinds. Methods provided are tested and working in the Charter Communcations production enviroment.
27              
28             =cut
29              
30 2     2   22160 use 5.010001;
  2         7  
31 2     2   10 use strict;
  2         4  
  2         41  
32 2     2   9 use warnings;
  2         3  
  2         40  
33 2     2   9 use Data::Dumper;
  2         4  
  2         73  
34 2     2   1320 use IO::Socket::SSL;
  2         148760  
  2         21  
35 2     2   1900 use LWP::UserAgent;
  2         85719  
  2         82  
36 2     2   20 use HTTP::Request;
  2         6  
  2         49  
37 2     2   1001 use MIME::Base64 qw();
  2         1097  
  2         324  
38 2     2   809 use Net::SolarWinds::Log;
  2         9  
  2         61  
39 2     2   1044 use JSON qw();
  2         13866  
  2         59  
40 2     2   885 use URI::Encode qw(uri_encode);
  2         20924  
  2         132  
41 2     2   19 use POSIX qw(strftime);
  2         5  
  2         21  
42              
43             our $VERSION="1.21";
44              
45 2     2   134 use base qw(Net::SolarWinds::ConstructorHash Net::SolarWinds::LogMethods Net::SolarWinds::Helper);
  2         5  
  2         913  
46 2     2   16 use constant RESULT_CLASS=>'Net::SolarWinds::Result';
  2         4  
  2         86  
47 2     2   10 use constant TIMESTAMP_FORMAT=>'%m/%d/%Y %H:%M:%S';
  2         4  
  2         72  
48 2     2   680 use Net::SolarWinds::Result;
  2         5  
  2         201  
49              
50              
51             =head1 GLOBAL OBJECTS
52              
53             =over 4
54              
55             =item * $Net::SolarWinds::REST::JSON
56              
57             This is a JSON object with the following options endabled: JSON->new->allow_nonref->utf8
58              
59             =cut
60              
61             # Global JSON OBJECT
62             our $JSON=JSON->new->allow_nonref->utf8;
63              
64             =item * my $json=$class->get_json;
65              
66             Returns the class level JSON object.
67              
68             =cut
69              
70 0     0 1 0 sub get_json { return $JSON; }
71              
72             =item * $Net::SolarWinds::REST::UA
73              
74             This is a LWP::UserAgent used to talk to CPM servers
75              
76             =cut
77              
78             # Global UA object
79             our $UA=LWP::UserAgent->new;
80             # Turn off SSL Verification
81             $UA->ssl_opts(
82             SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
83             SSL_hostname => '',
84             verify_hostname => 0
85             );
86              
87              
88             =item * my $ua=$class->get_ua;
89              
90             Returns the Class level UA object.
91              
92             =cut
93              
94 0     0 1 0 sub get_ua { return $UA; }
95              
96             =back
97              
98             =cut
99              
100             =head1 Class Constants
101              
102             The following constants are accessable via: Net::SolarWinds::REST->CONSTANT
103              
104             DEFAULT_USER=>'admin';
105             DEFAULT_PASS=>'ChangeMe';
106             DEFAULT_SERVER=>'SolarWindsServer';
107             DEFAULT_PORT=>17778;
108             DEFAULT_PROTO=>'https';
109             BASE_URI=>'%s://%s:%i/SolarWinds/InformationService/v3/Json/%s';
110             LOG_CLASS=>'Net::SolarWinds::Log';
111              
112             =cut
113              
114 2     2   13 use constant DEFAULT_USER=>'admin';
  2         4  
  2         87  
115 2     2   11 use constant DEFAULT_PASS=>'ChangeMe';
  2         4  
  2         80  
116 2     2   10 use constant DEFAULT_SERVER=>'SolarWindsServer';
  2         6  
  2         66  
117 2     2   29 use constant DEFAULT_PORT=>17778;
  2         4  
  2         77  
118 2     2   10 use constant DEFAULT_PROTO=>'https';
  2         4  
  2         80  
119 2     2   10 use constant BASE_URI=>'%s://%s:%i/SolarWinds/InformationService/v3/Json/%s';
  2         3  
  2         79  
120 2     2   13 use constant LOG_CLASS=>'Net::SolarWinds::Log';
  2         24  
  2         7177  
121              
122             =head2 OO Methods
123              
124             This section covers the OO Methods of the class.
125              
126             =over 4
127              
128             =item * Object Constructor.
129              
130             The object constructor takes key=>value pairs all aguments are optional, default values are pulled from the constants DEFAULT_*.
131              
132             my $sw=new Net::SolarWinds::REST(
133             USER =>'User',
134             PASS =>'Passxxx',
135             SERVER =>'SolarwindsServer',
136             PORT =>17778,
137             PROTO =>'https',
138             # Logging is not enabled by default!
139             log=> Net::SolarWinds::Log->new('/var/log/Solarwinds.log')
140             );
141              
142             =cut
143              
144             sub new {
145 3     3 0 1936 my ($class,%args)=@_;
146              
147 3         12 foreach my $key (qw(USER PASS SERVER PORT PROTO)) {
148 15         34 my $method="DEFAULT_$key";
149 15 50       38 next if exists $args{$key};
150 15         88 $args{$key}=$class->$method;
151             }
152            
153 3         25 my $self=$class->SUPER::new(%args);
154              
155             $self->{header}=[
156 3         50 Authorization=>'Basic '.MIME::Base64::encode_base64($self->{USER} . ':' . $self->{PASS}),
157             'Content-Type' => 'application/json',
158             ];
159 3         19 return $self;
160             }
161              
162             =item * my $request=$self->build_request('GET|POST|PUT|DELETE',$path,undef|$ref);
163              
164             Creates an HTTP::Request object with the default options set.
165              
166             =cut
167              
168             sub build_request {
169 0     0 1 0 my ($self,$method,$path,$data)=@_;
170 0         0 my $uri=sprintf $self->BASE_URI,@{$self}{qw(PROTO SERVER PORT )},$path;
  0         0  
171              
172 0         0 my $content=undef;
173 0         0 my $headers=[@{$self->{header}}];
  0         0  
174 0 0       0 if(defined($data)) {
175 0         0 $content=$self->get_json->encode($data);
176 0         0 push @{$headers},'Content-Length'=>length($content);
  0         0  
177             }
178 0         0 my $request=HTTP::Request->new($method,$uri,$headers,$content);
179 0         0 $self->log_debug($request->as_string);
180 0         0 return $request;
181             }
182              
183             =item * my $request=$self->NodeUnmanage($nodeID,$start,$end,$state);
184              
185             Used to manage and unmanage a node.
186              
187             Optional Arguments:
188             $start '11/18/2015 11:37:25'
189             $end '11/20/2015 11:37:25'
190             $state
191             To Manage: JSON::false
192             To UnManage: JSON::true
193              
194             Default interal values are
195              
196             $start=now
197             $end=now + 10 years
198             $state=JSON::true
199              
200             =cut
201            
202             sub NodeUnmanage {
203 0     0 1 0 my ($self,$nodeid,$start,$end,$state)=@_;
204 0         0 my $id='N:'.$nodeid;
205              
206 0 0       0 $start=$self->now_timestamp unless defined($start);
207 0 0       0 $end=$self->future_timestamp unless defined($end);
208 0 0       0 $state=JSON::true unless defined($state);
209 0         0 my $request=$self->build_request('POST','Invoke/Orion.Nodes/Unmanage',[$id,$start,$end,$state]);
210 0         0 my $result=$self->run_request($request);
211              
212 0         0 return $result;
213             }
214              
215             =item * my $now=$self->now_timestamp;
216              
217             Returns a timestamp of now.
218              
219             =cut
220              
221             sub now_timestamp {
222 0     0 1 0 my ($self)=@_;
223 0         0 my $now=strftime($self->TIMESTAMP_FORMAT,localtime);
224 0         0 return $now;
225             }
226              
227             =item * my $future=$self->future_timestamp;
228              
229             Returns a timestamp of 10 years for now ( plus or minus a few seconds )
230              
231             =cut
232              
233             sub future_timestamp {
234 0     0 1 0 my ($self)=@_;
235 0         0 my $now=time;
236             # 10 years from now!
237 0         0 $now +=60 * 60 * 24 * 365 * 10;
238 0         0 my $ts=strftime($self->TIMESTAMP_FORMAT,localtime($now));
239 0         0 return $ts;
240             }
241              
242             =item * my $result=$self->run_request($request);
243              
244             Takes a given HTTP::Request object and runs it returing a Net::SolarWinds::Result object.
245             What the object contains is relative to the request run.. If the result code of the request
246             was not a 20x value then the object is false.
247              
248             =cut
249              
250             sub run_request {
251 0     0 1 0 my ($self,$request)=@_;
252              
253 0         0 $self->log_debug("Sending: ",$request->as_string);
254 0         0 my $response=$self->get_ua->request($request);
255 0         0 $self->log_debug("Got back",$response->as_string);
256 0         0 my $content=$response->decoded_content;
257 0 0       0 if($response->is_success) {
258 0 0       0 if($content=~ /^\s*[\[\{]/s) {
259 0         0 my $data=eval {$self->get_json->decode($content)};
  0         0  
260 0 0       0 if($@) {
261 0         0 return $self->RESULT_CLASS->new_false("Code: [".$response->code."] JSON Decode error [$@] Content: $content",$response);
262             } else {
263 0         0 return $self->RESULT_CLASS->new_true($data,$response);
264             }
265             } else {
266 0         0 return $self->RESULT_CLASS->new_true($content,$response);
267             }
268             } else {
269 0         0 return $self->RESULT_CLASS->new_false("Code: [".$response->code."] http error [".$response->status_line."] Content: $content",$response);
270             }
271             }
272              
273             =item * my $result=$self->DiscoverInterfacesOnNode($nodeId)
274              
275             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
276              
277             =cut
278              
279             sub DiscoverInterfacesOnNode {
280 0     0 1 0 my ($self,$nodeId)=@_;
281              
282             # force a string;
283 0         0 $nodeId .='';
284              
285 0         0 $self->log_info("Started Discoverying interfaces on nodeid: $nodeId");
286 0         0 my $request=$self->build_request('POST','Invoke/Orion.NPM.Interfaces/DiscoverInterfacesOnNode',[$nodeId]);
287 0         0 my $result=$self->run_request($request);
288 0         0 $self->log_info("Finished Discoverying interfaces on nodeid: $nodeId");
289              
290 0         0 return $result;
291             }
292              
293             =item * my $result=$self->DiscoverInterfaceMap($nodeId);
294              
295             Returns a Net::SolarWinds::Result object:
296              
297             When true it contains an anonymous hash that maps interface objects to interface names.
298             When false it contains why it failed.
299              
300             =cut
301              
302             sub DiscoverInterfaceMap {
303 0     0 1 0 my ($self,$node_id)=@_;
304              
305 0         0 $self->log_info("starting node_id: $node_id");
306 0         0 my $result=$self->DiscoverInterfacesOnNode($node_id);
307 0         0 $self->log_info("stopping");
308 0         0 return $self->build_interface_result_map($result);
309             }
310              
311             =item * my $result=$self->build_interface_result_map($result);
312              
313             Internals of DiscoverInterfaceMap
314              
315             =cut
316              
317             sub build_interface_result_map {
318 0     0 1 0 my ($self,$result)=@_;
319              
320 0         0 $self->log_info("starting");
321 0 0       0 unless($result) {
322 0         0 $self->log_error("failed to build interface map error was: $result");
323 0         0 $self->log_info("stopping");
324 0         0 return $result;
325             }
326 0         0 my $list=$result->get_data->{DiscoveredInterfaces};
327              
328 0         0 my $map={};
329 0         0 foreach my $int (@{$list}) {
  0         0  
330 0         0 my $caption=$int->{Caption};
331 0         0 my @list=$self->InterfaceCaptionTranslation($caption);
332 0         0 foreach my $ifname (@list) {
333 0         0 $map->{$ifname}=$int;
334             }
335             }
336              
337 0         0 $self->log_info("stopping");
338 0         0 return $self->RESULT_CLASS->new_true($map,$list);
339             }
340              
341             =item * my @names=$self->InterfaceCaptionTranslation($Caption);
342              
343             Takes an interface caption and converts it to a list of valid interface names that should match what is on a given device.
344              
345             =cut
346              
347             sub InterfaceCaptionTranslation {
348 0     0 1 0 my ($self,$caption)=@_;
349              
350 0         0 $self->log_info("starting");
351 0         0 my @list;
352 0 0       0 if($caption=~ s/\s\\x\{b7\}.*$//s > 0) {
353 0         0 push @list,$caption;
354             } else {
355 0         0 push @list,split /\s+-\s+/,$caption;
356             }
357              
358 0         0 $self->log_info("stopping");
359 0         0 return @list;
360             }
361              
362             =item * my $result=$self->NodeInterfaceAddDefaultPollers($nodeId,$interfaec_ref);
363              
364             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
365             $interface_ref represents object listed from the DiscoverInterfacesOnNode that need to be added to the default pollers.
366              
367             =cut
368              
369             sub NodeInterfaceAddDefaultPollers {
370 0     0 1 0 my ($self,$nodeId,$data)=@_;
371              
372 0         0 $self->log_info("starting");
373             # force a string;
374 0         0 $nodeId .='';
375            
376 0         0 my $request=$self->build_request('POST','Invoke/Orion.NPM.Interfaces/AddInterfacesOnNode',[$nodeId,$data,'AddDefaultPollers']);
377 0         0 my $result=$self->run_request($request);
378              
379 0         0 $self->log_info("stopping");
380 0         0 return $result;
381             }
382              
383             =item * my $result=$self->NodeAddInterface($node_id,[$interface]);
384              
385             Adds an interface to the cpm for the node but does not add any pollers.
386              
387             =cut
388              
389             sub NodeAddInterface {
390 0     0 1 0 my ($self,$node_id,$data)=@_;
391              
392 0         0 $self->log_info("starting");
393 0         0 my $request=$self->build_request('POST','Invoke/Orion.NPM.Interfaces/AddInterfacesOnNode',[$node_id,$data,'AddNoPollers']);
394 0         0 my $result=$self->run_request($request);
395 0         0 $self->log_info("stopping");
396              
397 0         0 return $result;
398             }
399              
400             =item * my $result=$self->NodeInterfaceCustomProperties($nodeId,$interfaceId,$hash_ref|undef);
401              
402             Used to get or set custom properties of an interfaec on a node.
403             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
404              
405             =cut
406              
407             sub NodeInterfaceCustomProperties {
408 0     0 1 0 my ($self,$nodeId,$interfaceId,$data)=@_;
409              
410 0         0 my $request;
411 0         0 $self->log_info("starting");
412 0 0       0 if($data) {
413 0         0 $request=$self->build_request('POST',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/Interfaces/InterfaceID=$interfaceId/CustomProperties",$data);
414             } else {
415 0         0 $request=$self->build_request('GET',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/Interfaces/InterfaceID=$interfaceId/CustomProperties");
416             }
417 0         0 my $result=$self->run_request($request);
418 0         0 $self->log_info("stopping");
419 0         0 return $result;
420             }
421              
422             =item * my $query=$self->query_finder(@args);
423              
424             Returns formatted SWQL query within a given function. It finds the corrisponding constant via the $self->LOG_CLASS->lookback(2) call back.
425              
426             =cut
427              
428             sub query_lookup {
429 1     1 0 17 my ($self,@args)=@_;
430              
431             # use the logging class look back to find our method.
432 1         14 my $hash=$self->LOG_CLASS->lookback(2);
433              
434 1         3 my $method=$hash->{sub};
435 1         7 $method=~ s/^.*::([^:]+)/$1/s;
436 1         10 $self->log_debug("Starting look up of query: $method");
437 1         6 my $query=$self->get_query($method);
438 1         5 $self->log_debug("Finished look up of query: $method");
439              
440 1 50       4 $self->log_debug("Preparing query: $method Args: [",join(',',map { defined($_) ? qq{"$_"} : '""' } @args),']');
  1         11  
441 1         6 my $swql=$self->prepare_query($query,@args);
442              
443 1         7 $self->log_debug("Preparing query: $method Looks like: $swql");
444              
445 1         8 return $swql;
446             }
447              
448             =item * my $prepared=$self->prepare_query($query,@args);
449              
450             Just a wrapper for: sprintf $query,@args
451              
452             =cut
453              
454             sub prepare_query {
455 1     1 1 3 my ($self,$query,@args)=@_;
456              
457 1         6 return sprintf $query,@args;
458             }
459              
460             =item * my $raw_query=$self->get_query($method);
461              
462             Does an internal method lookup of SWQL_$method and returns the results of the method
463              
464             =cut
465              
466             sub get_query {
467 1     1 1 3 my ($self,$method)=@_;
468              
469 1         4 my $constant="SWQL_$method";
470 1 50       8 return 'QUERY NOT FOUND' unless $self->can($constant);
471              
472 1         6 return $self->$constant;
473             }
474              
475             =item * my $result=$self->getInterfacesOnNode($NodeID);
476              
477             Returns a Net::SolarWinds::Result Object
478              
479             when true: Gets the interfaces from the node
480             when false: returns why it failed
481              
482             =cut
483              
484             sub getInterfacesOnNode {
485 0     0 1   my ($self,$node_id)=@_;
486 0           my $query=$self->query_lookup($node_id);
487              
488 0           $self->log_info("starting $node_id");
489 0           my $result=$self->Query($query);
490              
491 0 0         return $result unless $result;
492              
493 0           my $list=$result->get_data->{results};
494 0           my $ints={};
495              
496 0           foreach my $int (@{$list}) {
  0            
497 0           my @list=$self->InterfaceCaptionTranslation($int->{Caption});
498 0           foreach my $ifname (@list) {
499 0           $ints->{$ifname}=$int;
500             }
501             }
502              
503 0           $self->log_info("stopping");
504 0           return $self->RESULT_CLASS->new_true($ints);
505             }
506              
507             =item * my $result=$self->GetAlertSettings($nodeid);
508              
509             Returns a Net::SolarWinds::Result Object
510              
511             when true: Contains the list of Orion.ForecastCapacity, for the given node
512             when false: returns why it failed
513              
514             =cut
515              
516             sub GetAlertSettings {
517 0     0 1   my ($self,$node_id)=@_;
518 0           $self->log_info("starting $node_id");
519 0           my $query=$self->query_lookup($node_id);
520 0           my $result=$self->Query($query);
521 0           $self->log_info("finished $node_id");
522 0           return $result;
523             }
524              
525             =item * my $result=$self->NodeCustomProperties($nodeId,$hash_ref|undef);
526              
527             Used to get or set custom properties of a node.
528             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
529              
530             =cut
531              
532             sub NodeCustomProperties {
533 0     0 1   my ($self,$nodeId,$data)=@_;
534              
535              
536 0           my $request;
537 0 0         if($data) {
538            
539 0           $self->log_info("starting node_id: $nodeId mode: POST");
540 0           $request=$self->build_request('POST',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/CustomProperties",$data);
541             } else {
542 0           $self->log_info("starting node_id: $nodeId mode: GET");
543 0           $request=$self->build_request('GET',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/CustomProperties");
544             }
545 0           my $result=$self->run_request($request);
546 0           $self->log_info("stopping");
547            
548 0           return $result;
549             }
550              
551             =item * my $result=$self->Query($sql);
552              
553             =item * my $result=$self->Query({"query"=>"SELECT Uri FROM Orion.Pollers WHERE PollerID=@p ORDER BY PollerID WITH ROWS 1 TO 3 WITH TOTALROWS","parameters"=>{"p"=>9}});
554              
555             Used to run an sql query against CPM.
556             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
557              
558              
559              
560             =cut
561              
562             sub Query {
563 0     0 1   my ($self,$sql)=@_;
564 0           $self->log_info("starting");
565 0           my $result;
566 0 0 0       if(ref($sql) and ref($sql) eq 'HASH') {
567 0           $self->log_info("called in post mode");
568 0           $self->log_debug(Dumper($sql));
569 0           my $path='Query';
570 0           my $request=$self->build_request('POST',$path,$sql);
571 0           $result=$self->run_request($request);
572             } else {
573 0           $self->log_info("called in get mode");
574 0           $self->log_debug("$sql");
575 0           my $path='Query?query='.uri_encode($sql);
576 0           my $request=$self->build_request('GET',$path);
577 0           $result=$self->run_request($request);
578 0           $self->log_info("stopping");
579             }
580 0           return $result;
581             }
582              
583             =item * my $result=$self->BulkUpdate({uris=>["swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=1", "swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=2", "swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=3"],properties=>{"NextPoll"=>"7/1/2014 9:06:19 AM","NextRediscovery"=>"7/1/2014 2:59:09 PM"}});
584              
585             Used to update uris in bulk, returns a Net::SolarWinds::Result object.
586              
587             =cut
588              
589             sub BulkUpdate {
590 0     0 1   my ($self,$ref)=@_;
591 0           $self->log_info("starting");
592 0           my $request=$self->build_request('POST','BulkUpdate',$ref);
593 0           my $result=$self->run_request($request);
594 0           $self->log_info("stopping");
595              
596 0           return $result
597             }
598              
599             =item * my $result=$self->BulkDelete({uris=>["swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=1", "swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=2", "swis://dev-che-mjag-01./Orion/Orion.Nodes/NodeID=4/Volumes/VolumeID=3"]});
600              
601             Used to delete uris in bulk, returns a Net::SolarWinds::Result object.
602              
603             =cut
604              
605             sub BulkDelete {
606 0     0 1   my ($self,$ref)=@_;
607 0           $self->log_info("starting");
608 0           my $request=$self->build_request('POST','BulkDelete',$ref);
609 0           my $result=$self->run_request($request);
610 0           $self->log_info("stopping");
611              
612 0           return $result
613             }
614              
615             =item * my $result=$self->getNodesByIp($ip);
616              
617             Find a list of nodes by a given ip.
618             Returns a Net::SolarWinds::Result Object: When true it contains an array ref of the results, when false it contains the error.
619              
620             =cut
621              
622             sub getNodesByIp {
623 0     0 1   my ($self,$ip)=@_;
624 0           $self->log_info("starting $ip");
625 0           my $query=$self->query_lookup($ip);
626 0           my $result=$self->Query($query);
627 0           $self->log_info("stopping");
628 0           return $result;
629             }
630              
631             =item * my $result=$self->getNodesByDisplayName($hostname);
632              
633             Find a list of nodes by a given hostname.
634             Returns a Net::SolarWinds::Result Object: When true it contains an array ref of the results, when false it contains the error.
635              
636             =cut
637              
638             sub getNodesByDisplayName {
639 0     0 1   my ($self,$ip)=@_;
640 0           $self->log_info("starting $ip");
641 0           my $query=$self->query_lookup($ip,$ip);
642 0           my $result=$self->Query($query);
643 0           $self->log_info("stopping");
644 0           return $result;
645             }
646              
647             =item * my $result=$self->getNodesByID($nodeid);
648              
649             Returns a Net::SolarWinds::Result object that contains a list of objects that matched that nodeid
650              
651             =cut
652              
653             sub getNodesByID {
654 0     0 1   my ($self,$id)=@_;
655 0           $self->log_info("starting");
656 0           my $query=$self->query_lookup($id);
657 0           my $result=$self->Query($query);
658              
659 0           $self->log_info("stopping");
660 0           return $result;
661             }
662              
663             =item * my $result=$self->createNode(key=>value);
664              
665             Creates a node.
666             Returns a Carter::Result Object: Retuns a data structure on sucess returns why it faield on false.
667              
668             Note, there are no presets when using this method!
669              
670             =cut
671              
672             sub nopresetsCreateNode {
673 0     0 0   my ($self,%args)=@_;
674              
675 0           $self->log_info("starting");
676             # Caption
677              
678 0           my $path='Create/Orion.Nodes';
679 0           my $request=$self->build_request('POST',$path,{%args});
680 0           my $result=$self->run_request($request);
681              
682 0 0         unless($result) {
683 0           $self->log_error("Failed to create node error was: $result");
684 0           $self->log_info("stopping");
685 0           return $result;
686             }
687 0           my $swis=$result->get_data;
688 0           $swis=~ s/(?:^"|"$)//sg;
689 0           my ($node_id)=$swis=~ /(\d+)$/s;
690              
691 0           $self->log_info("stopping");
692 0           return $self->RESULT_CLASS->new_true({Uri=>$swis,NodeID=>$node_id});
693             }
694              
695              
696             =item * my $result=$self->createNode(key=>value);
697              
698             Creates a node.
699             Returns a Carter::Result Object: Retuns a data structure on sucess returns why it faield on false.
700              
701             # the defautl key/value list is
702             qw(
703             ObjectSubType SNMP
704             EntityType Orion.Nodes
705             DynamicIP false
706             EngineID 1
707             Status 1
708             UnManaged false
709             Allow64BitCounters true
710             ObjectSubType SNMP
711             SNMPVersion 2
712             Community public
713             VendorIcon 8072.gif
714             NodeDescription Hardware
715              
716             ),
717             IOSImage=>"",
718             IOSVersion=>"",
719             Pollinterval=>60,
720             SysObjectID=>"1.3.6.1.4.1.8072.3.2.10",
721             MachineType=>"net-snmp - Linux",
722             StatCollection=>10,
723             CPULoad=>"-2",
724             MemoryUsed=>"-2",
725             PercentMemoryUsed=>"-2",
726             BufferNoMemThisHour=>"0",
727             BufferNoMemToday=>"0",
728             BufferSmMissThisHour=>"0",
729             BufferSmMissToday=>"0",
730             BufferMdMissThisHour=>"0",
731             BufferMdMissToday=>"0",
732             BufferBgMissThisHour=>"0",
733             BufferBgMissToday=>"0",
734             BufferLgMissThisHour=>"0",
735             BufferLgMissToday=>"0",
736             BufferHgMissThisHour=>"0",
737             BufferHgMissToday=>"0",
738            
739              
740             =cut
741              
742             sub createNode {
743 0     0 1   my ($self,%args)=@_;
744              
745 0           $self->log_info("starting");
746             # Caption
747 0           %args=(
748             qw(
749             ObjectSubType SNMP
750             EntityType Orion.Nodes
751             DynamicIP false
752             EngineID 1
753             Status 1
754             UnManaged false
755             Allow64BitCounters true
756             ObjectSubType SNMP
757             SNMPVersion 2
758             Community public
759             VendorIcon 8072.gif
760             NodeDescription Hardware
761              
762             ),
763             IOSImage=>"",
764             IOSVersion=>"",
765             Pollinterval=>60,
766             SysObjectID=>"1.3.6.1.4.1.8072.3.2.10",
767             MachineType=>"net-snmp - Linux",
768             StatCollection=>10,
769             CPULoad=>"-2",
770             MemoryUsed=>"-2",
771             PercentMemoryUsed=>"-2",
772             BufferNoMemThisHour=>"0",
773             BufferNoMemToday=>"0",
774             BufferSmMissThisHour=>"0",
775             BufferSmMissToday=>"0",
776             BufferMdMissThisHour=>"0",
777             BufferMdMissToday=>"0",
778             BufferBgMissThisHour=>"0",
779             BufferBgMissToday=>"0",
780             BufferLgMissThisHour=>"0",
781             BufferLgMissToday=>"0",
782             BufferHgMissThisHour=>"0",
783             BufferHgMissToday=>"0",
784             %args
785             );
786              
787 0 0         unless(exists $args{IPAddress}) {
788 0           $self->log_error("IPAddress must be set");
789 0           $self->log_info("stopping");
790 0           return $self->RESULT_CLASS->new_false("IPAddress must be set");
791             }
792              
793             # start building our required but often times missing key value pairs
794 0 0         $args{IPAddressGUID}=$self->ip_to_gui($args{IPAddress}) unless exists $args{IPAddressGUID};
795 0 0         $args{Caption}=$self->ip_to_reverse_hex($args{IPAddress}) unless exists $args{Caption};
796            
797 0           $self->log_info('stopping');
798              
799 0           return $self->nopresetsCreateNode(%args);
800             }
801              
802             =item * my $result=$self->getNodeUri($node_id);
803              
804             When true the Net::SolarWinds::Result object contains the node uri.
805             When false it contains why it failed.
806              
807             =cut
808              
809             sub getNodeUri {
810 0     0 1   my ($self,$node_id)=@_;
811              
812 0           $self->log_info("starting");
813             #my $query="Select Uri from Orion.Nodes where NodeId=$node_id";
814 0           my $query=$self->query_lookup($node_id);
815              
816 0           my $result=$self->Query($query);
817              
818 0 0         unless($result) {
819 0           $self->log_error("could not get node uri error was: $result");
820 0           $self->log_info("stopping");
821 0           return $result;
822             }
823              
824 0 0         unless($#{$result->get_data->{results}} >-1) {
  0            
825 0           $self->log_error("NodeId: $node_id not found!");
826 0           $self->log_info("stopping");
827 0           return $self->RESULT_CLASS->new_false("NodeId: $node_id not found!")
828             }
829              
830 0           $self->log_info("stopping");
831 0           return $self->RESULT_CLASS->new_true($result->get_data->{results}->[0]->{Uri});
832              
833             }
834              
835             =item * my $result=$self->deleteSwis($uri);
836              
837             Returns a charter result object showing status.
838              
839             =cut
840              
841             sub deleteSwis {
842 0     0 1   my ($self,$uri)=@_;
843 0           $self->log_info("starting");
844 0           my $request=$self->build_request('DELETE',$uri);
845 0           my $result=$self->run_request($request);
846 0           $self->log_info("stopping");
847              
848 0           return $result;
849             }
850              
851             =item * my $result=$self->deleteNode($node_id);
852              
853             Deletes a given node.
854              
855             =cut
856              
857             sub deleteNode {
858 0     0 1   my ($self,$node_id)=@_;
859 0           my $path;
860              
861 0           $self->log_info("starting");
862 0 0         if(my $result=$self->getNodeUri($node_id)) {
863 0           $path=$result->get_data;
864             } else {
865 0           $self->log_error("Failed to delete node: $node_id error was: $result");
866 0           $self->log_info("stopping");
867 0           return $result;
868             }
869 0           my $request=$self->build_request('DELETE',$path);
870 0           my $result=$self->run_request($request);
871 0           $self->log_info("stopping");
872 0           return $result;
873             }
874              
875             =item * my $result=$self->getApplicationTemplate(@names);
876              
877             This is a wrapper for the Query interface. Returns the results that match applications by this name.
878              
879             =cut
880              
881             sub getApplicationTemplate {
882 0     0 1   my ($self,@names)=@_;
883              
884 0           $self->log_info("starting");
885 0           my $append=join ' OR ',map { sprintf q{Name='%s'},$_ } @names;
  0            
886 0           my $query=$self->query_lookup($append);
887            
888 0           my $result=$self->Query($query);
889 0           $self->log_info("stopping");
890 0           return $result;
891             }
892              
893             =item * my $result=$self->addTemplateToNode($node_id,$template_id);
894              
895             =item * my $result=$self->addTemplateToNode($node_id,$template_id,$cred_id);
896              
897             Adds a monitoring template with the default credentals to the node.
898             Returns true on success false on failure.
899              
900             =cut
901              
902             sub addTemplateToNode {
903 0     0 1   my ($self,$node_id,$template_id,$cred_id)=@_;
904 0 0         $cred_id=-4 unless defined($cred_id);
905 0           $self->log_info("starting node_id: $node_id template_id: $template_id credential_id: $cred_id");
906 0           my $request=$self->build_request(
907             'POST',
908             'Invoke/Orion.APM.Application/CreateApplication',
909             [$node_id,$template_id,$cred_id,JSON::true]
910             );
911 0           my $result=$self->run_request($request);
912 0 0         unless($result) {
913 0           $self->log_error("Failed to addTemplateToNode error was: $result");
914 0           $self->log_info("stopping");
915 0           return $result;
916             }
917              
918 0 0         if($result->get_data == -1) {
919 0           my $msg="TemplateID: $template_id all ready exists on node";
920 0           $self->log_error($msg);
921 0           $self->log_info("stopping");
922 0           return $self->RESULT_CLASS->new_false($msg);
923             }
924              
925 0           $self->log_info("stopping");
926 0           return $result;
927             }
928              
929             =item * my $result=$self->getTemplatesOnNode($node_id);
930              
931             Returns a Net::SolarWinds::Result object
932             When true it contains the templates on the node
933             when false it contains why it failed.
934              
935             =cut
936              
937             sub getTemplatesOnNode {
938 0     0 1   my ($self,$node_id)=@_;
939 0           $self->log_info("starting");
940 0           my $query=$self->query_lookup($node_id);
941 0           my $result=$self->Query($query);
942 0 0         unless($result) {
943 0           $self->log_error("failed to getTemplatesOnNode");
944 0           $self->log_info("stopping");
945 0           return $result;
946             }
947              
948 0           $self->log_info("stopping");
949 0           return $self->RESULT_CLASS->new_true($result->get_data->{results});
950             }
951              
952             =item * my $result=$self->UpdateNodeProps($nodeID,key=>values);
953              
954             Has 2 use cases Read/Write: When called with just the $nodeID the result object is populated with the node properties. When called with a hash the given values are pushed to the node. Returns a Net::SolarWinds::Result object: true on success false on failure.
955              
956             =cut
957              
958             sub UpdateNodeProps {
959 0     0 1   my ($self,$nodeID,%args)=@_;
960              
961 0           $self->log_info("starting node_id: $nodeID");
962 0           my $uri='swis://localhost/Orion/Orion.Nodes/NodeID='.$nodeID;
963              
964 0           my $request;
965 0 0         if(scalar(keys(%args))==0) {
966 0           $self->log_info("called in Read mode");
967 0           $request=$self->build_request('GET',$uri);
968             } else {
969 0           $self->log_info("called in Write mode");
970 0           $request=$self->build_request('POST',$uri,{%args});
971             }
972 0           my $result=$self->run_request($request);
973 0           $self->log_info("stopping $nodeID");
974 0           return $result;
975             }
976              
977              
978             =item * my $result=$self->AddPollerToNode($nodeID,$Poller);
979              
980             Adds a poller to a node.
981              
982             =cut
983              
984              
985             sub AddPollerToNode {
986 0     0 1   my ($self,$node_id,$poller)=@_;
987              
988 0           $self->log_info("starting node_id: $node_id poller: $poller");
989 0           my $result=$self->add_poller($node_id,'N',$poller);
990 0           $self->log_info("stopping node_id: $node_id poller: $poller");
991 0           return $result;
992             }
993              
994             =item * my $result=$self->add_poller($node_id,$t,$poller)
995              
996             Returns a Net::SolarWinds::Result object when true it returns the result information that shows the results of the poller being added.
997              
998             =cut
999              
1000             sub add_poller {
1001 0     0 1   my ($self,$node_id,$t,$poller)=@_;
1002              
1003 0           $self->log_info("starting object_id: $node_id type: $t poller: $poller");
1004              
1005 0           my $json={
1006             PollerType=>$poller,
1007             NetObjectType=>$t,
1008             NetObject=>$t.':'.$node_id,
1009             NetObjectID=>$node_id,
1010             };
1011              
1012 0           my $request=$self->build_request('POST','Create/Orion.Pollers',$json);
1013 0           my $result=$self->run_request($request);
1014 0 0         unless($result) {
1015 0           $self->log_error("failed to add poller to node_id: $node_id type: $t poller: $poller error was: $result");
1016 0           $self->log_info("stopping");
1017 0           return $result;
1018             }
1019 0           my $url=$result->get_data;
1020 0           $url=~ s/(?:^"|"$)//g;
1021              
1022 0           $self->log_info("stopping");
1023 0           return $self->RESULT_CLASS->new_true($url);
1024             }
1025              
1026             =item * my $result=$self->add_volume(key=>value);
1027              
1028             Creates a volume given the arguments passed in.
1029              
1030             Returns a Net::SolarWinds::Result object:
1031             When false it contains why it failed
1032             When true it returns a swis uri
1033              
1034             =cut
1035              
1036             sub add_volume {
1037 0     0 1   my ($self,%args)=@_;
1038              
1039 0           $self->log_info("starting");
1040 0           my $json={
1041             VolumeIndex=>2,
1042             Caption=>"/",
1043             VolumeDescription=>"/",
1044             Status=>1,
1045             VolumeType=>"Fixed Disk",
1046             VolumeTypeIcon=>"FixedDisk.gif",
1047             VolumeSpaceAvailable=>0,
1048             VolumeSize=>0,
1049             VolumePercentUsed=>0,
1050             VolumeSpaceUsed=>0,
1051             VolumeTypeID=>4,
1052             PollInterval=>240,
1053             StatCollection=>15,
1054             RediscoveryInterval=>30,
1055             ,%args
1056             };
1057              
1058 0           my $request=$self->build_request('POST','Create/Orion.Volumes',$json);
1059 0           my $result=$self->run_request($request);
1060              
1061 0           $self->log_info("stopping");
1062 0           return $result;
1063             }
1064              
1065             =item * my $result=$self->getVolumeTypeMap;
1066              
1067             Returns a Net::SolarWinds::Result Object
1068             When true Returns the volume type map.
1069             When false it returns why it failed.
1070              
1071             =cut
1072              
1073             sub getVolumeTypeMap {
1074 0     0 1   my ($self)=@_;
1075              
1076 0           $self->log_info("starting");
1077 0           my $query=$self->SWQL_getNodesByIp;
1078 0           my $result=$self->Query($query);
1079 0 0         unless($result) {
1080 0           $self->log_error("Failed to get getVolumeTypeMap error was: $result");
1081 0           $self->log_info("stopping");
1082 0           return $result;
1083             }
1084              
1085 0           my $list=$result->get_data->{results};
1086              
1087 0           my $map={};
1088 0           foreach my $type (@{$list}) {
  0            
1089 0           $map->{$type->{VolumeType}}=$type;
1090             }
1091              
1092 0           $self->log_info("stopping");
1093 0           return $self->RESULT_CLASS->new_true($map);
1094             }
1095              
1096              
1097             =item * my $result=$self->getEngines;
1098              
1099             Returns a Net::SolarWinds::Result object:
1100             When true it contains the list of poller engins.
1101             When false it contains why it failed.
1102              
1103             =cut
1104              
1105             sub getEngines {
1106 0     0 1   my ($self)=@_;
1107              
1108 0           my $result=$self->Query($self->SWQL_getEngines);
1109              
1110 0           return $result;
1111             }
1112              
1113             =item * my $result=$self->getEngine($engine);
1114              
1115             Returns a Net::SolarWinds::Result Object:
1116             When true it contains the list of matching engines.
1117             When false it cointains why it failed.
1118              
1119             Notes: if no matching engines were found the result object can be true.. but will not contain any data.
1120              
1121             =cut
1122              
1123             sub getEngine {
1124 0     0 1   my ($self,$engine)=@_;
1125              
1126 0           my $result=$self->Query($self->query_lookup($engine,$engine));
1127              
1128 0 0         return $result unless $result;
1129             }
1130              
1131             =item * my $result=$self->getVolumeMap($nodeID);
1132              
1133             Returns a Net::SolarWinds::Result object:
1134             When true it contains a hash that maps volumes to objects.
1135             When false it returns why it failed.
1136              
1137             =cut
1138              
1139             sub getVolumeMap {
1140 0     0 1   my ($self,$node_id)=@_;
1141              
1142 0           $self->log_info("starting");
1143 0           my $query=$self->query_lookup($node_id);
1144 0           my $result=$self->Query($query);
1145 0 0         unless($result) {
1146 0           $self->log_error("Failed to get getVolumeMap for node_id: $node_id error was: $result");
1147 0           $self->log_info("stopping");
1148 0           return $result;
1149             }
1150              
1151 0           my $list=$result->get_data->{results};
1152 0           my $map={};
1153              
1154             # set our max volume index to 1 if we don't have any volumes on this node
1155 0 0         my $MaxVolumeIndex=$#{$list} > -1 ? $list->[0]->{VolumeIndex} : 1;
  0            
1156              
1157 0           foreach my $vol (@{$list}) {
  0            
1158             # assume no duplicates..
1159 0           $map->{$vol->{Caption}}=$vol;
1160             }
1161              
1162 0           $self->log_info("stopping");
1163 0           return $self->RESULT_CLASS->new_true({'map'=>$map,MaxVolumeIndex=>$MaxVolumeIndex});
1164              
1165             }
1166              
1167             =item * my $result=$self->getSwisProps($uri);
1168              
1169             Returns a Net::SolarWinds::Result object:
1170             When true it the uri is set in the result hash
1171             when false the explanation as to why it failed is gven.
1172              
1173             =cut
1174              
1175             sub getSwisProps {
1176 0     0 1   my ($self,$uri)=@_;
1177 0           $self->log_info("starting");
1178 0           my $request=$self->build_request('GET',$uri);
1179 0           my $result=$self->run_request($request);
1180 0           $self->log_info("stopping");
1181 0           return $result;
1182             }
1183              
1184             =item * my $result=$self->GetNodePollers($node_id,"N|V|I");
1185              
1186             Returns a Net::SolarWinds::Result Object that contains the nodes when true when false it contains why it failed.
1187              
1188             =cut
1189              
1190             sub GetNodePollers {
1191 0     0 1   my ($self,$node_id,$type)=@_;
1192 0 0         $type='N' unless defined($type);
1193 0           $self->log_info("starting node_id: $node_id type: $type");
1194 0           my $query=$self->query_lookup($node_id,$type);
1195 0           my $result=$self->Query($query);
1196              
1197 0 0         unless($result) {
1198 0           $self->log_error("Failed to GetNodePollers on node_id: $node_id type: $type");
1199 0           $self->log_info("stopping");
1200 0           return $result;
1201             }
1202              
1203 0           my $list=$result->get_data->{results};
1204 0           my $pollers=[];
1205 0           foreach my $poller (@{$list}) {
  0            
1206 0           my $result=$self->getSwisProps('swis://localhost/Orion/Orion.Pollers/PollerID='.$poller->{PollerID});
1207 0 0         return unless $result;
1208 0           push @{$pollers},$result->get_data;
  0            
1209             }
1210 0           $self->log_info("stopping");
1211 0           return $self->RESULT_CLASS->new_true($pollers);
1212             }
1213              
1214             =item * my $result=$self->UpdateUri($uri,%args);
1215              
1216             Read/Write Interface used update or get the contents of $uri. Returns a Net::SolarWinds::Result object. Write Mode is used when %args contains values Read Mode is used when %args is empty
1217              
1218             =cut
1219              
1220             sub UpdateUri {
1221 0     0 1   my ($self,$uri,%args)=@_;
1222              
1223 0           $self->log_info("starting Uri: $uri");
1224 0           my $request;
1225 0 0         if(scalar(keys(%args))==0) {
1226 0           $self->log_info("called in Read mode");
1227 0           $request=$self->build_request('GET',$uri);
1228             } else {
1229 0           $self->log_info("called in Write mode");
1230 0           $request=$self->build_request('POST',$uri,{%args});
1231             }
1232 0           my $result=$self->run_request($request);
1233 0           $self->log_info("stopping Uri $uri");
1234 0           return $result;
1235             }
1236              
1237             =back
1238              
1239             =head1 SEE ALSO
1240              
1241             Net::SolarWinds::REST::Batch
1242              
1243             =head1 AUTHOR
1244              
1245             Michael Shipper
1246              
1247             =head1 COPYRIGHT AND LICENSE
1248              
1249             Copyright (C) 2016 by Mike Shipper
1250              
1251             This library is free software; you can redistribute it and/or modify
1252             it under the same terms as Perl itself, either Perl version 5.10.1 or,
1253             at your option, any later version of Perl 5 you may have available.
1254              
1255             =cut
1256              
1257             1;
1258             __END__