File Coverage

blib/lib/Net/SolarWinds/REST.pm
Criterion Covered Total %
statement 94 470 20.0
branch 3 74 4.0
condition 0 3 0.0
subroutine 27 68 39.7
pod 40 45 88.8
total 164 660 24.8


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   22823 use 5.010001;
  2         5  
31 2     2   7 use strict;
  2         2  
  2         32  
32 2     2   6 use warnings;
  2         1  
  2         42  
33 2     2   5 use Data::Dumper;
  2         3  
  2         63  
34 2     2   1365 use IO::Socket::SSL;
  2         122822  
  2         13  
35 2     2   1594 use LWP::UserAgent;
  2         59053  
  2         69  
36 2     2   17 use HTTP::Request;
  2         3  
  2         74  
37 2     2   850 use MIME::Base64 qw();
  2         1050  
  2         41  
38 2     2   882 use Net::SolarWinds::Log;
  2         4  
  2         47  
39 2     2   617 use JSON qw();
  2         8163  
  2         42  
40 2     2   820 use URI::Encode qw(uri_encode);
  2         16175  
  2         111  
41 2     2   11 use POSIX qw(strftime);
  2         3  
  2         14  
42              
43             our $VERSION=1.18;
44              
45 2     2   117 use base qw(Net::SolarWinds::ConstructorHash Net::SolarWinds::LogMethods Net::SolarWinds::Helper);
  2         3  
  2         876  
46 2     2   27 use constant RESULT_CLASS=>'Net::SolarWinds::Result';
  2         2  
  2         74  
47 2     2   6 use constant TIMESTAMP_FORMAT=>'%m/%d/%Y %H:%M:%S';
  2         2  
  2         63  
48 2     2   771 use Net::SolarWinds::Result;
  2         4  
  2         180  
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   9 use constant DEFAULT_USER=>'admin';
  2         2  
  2         84  
115 2     2   8 use constant DEFAULT_PASS=>'ChangeMe';
  2         6  
  2         69  
116 2     2   7 use constant DEFAULT_SERVER=>'SolarWindsServer';
  2         2  
  2         64  
117 2     2   13 use constant DEFAULT_PORT=>17778;
  2         2  
  2         890  
118 2     2   8 use constant DEFAULT_PROTO=>'https';
  2         1  
  2         77  
119 2     2   6 use constant BASE_URI=>'%s://%s:%i/SolarWinds/InformationService/v3/Json/%s';
  2         2  
  2         62  
120 2     2   6 use constant LOG_CLASS=>'Net::SolarWinds::Log';
  2         2  
  2         6208  
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 824 my ($class,%args)=@_;
146              
147 3         8 foreach my $key (qw(USER PASS SERVER PORT PROTO)) {
148 15         19 my $method="DEFAULT_$key";
149 15 50       20 next if exists $args{$key};
150 15         64 $args{$key}=$class->$method;
151             }
152            
153 3         20 my $self=$class->SUPER::new(%args);
154              
155             $self->{header}=[
156 3         46 Authorization=>'Basic '.MIME::Base64::encode_base64($self->{USER} . ':' . $self->{PASS}),
157             'Content-Type' => 'application/json',
158             ];
159 3         12 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 10 my ($self,@args)=@_;
430              
431             # use the logging class look back to find our method.
432 1         10 my $hash=$self->LOG_CLASS->lookback(2);
433              
434 1         6 my $method=$hash->{sub};
435 1         7 $method=~ s/^.*::([^:]+)/$1/s;
436 1         8 $self->log_debug("Starting look up of query: $method");
437 1         5 my $query=$self->get_query($method);
438 1         3 $self->log_debug("Finished look up of query: $method");
439              
440 1 50       3 $self->log_debug("Preparing query: $method Args: [",join(',',map { defined($_) ? qq{"$_"} : '""' } @args),']');
  1         7  
441 1         4 my $swql=$self->prepare_query($query,@args);
442              
443 1         3 $self->log_debug("Preparing query: $method Looks like: $swql");
444              
445 1         5 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 2 my ($self,$query,@args)=@_;
456              
457 1         5 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         2 my $constant="SWQL_$method";
470 1 50       6 return 'QUERY NOT FOUND' unless $self->can($constant);
471              
472 1         4 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->NodeCustomProperties($nodeId,$hash_ref|undef);
508              
509             Used to get or set custom properties of a node.
510             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
511              
512             =cut
513              
514             sub NodeCustomProperties {
515 0     0 1   my ($self,$nodeId,$data)=@_;
516              
517              
518 0           my $request;
519 0 0         if($data) {
520            
521 0           $self->log_info("starting node_id: $nodeId mode: POST");
522 0           $request=$self->build_request('POST',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/CustomProperties",$data);
523             } else {
524 0           $self->log_info("starting node_id: $nodeId mode: GET");
525 0           $request=$self->build_request('GET',"swis://localhost/Orion/Orion.Nodes/NodeID=$nodeId/CustomProperties");
526             }
527 0           my $result=$self->run_request($request);
528 0           $self->log_info("stopping");
529            
530 0           return $result;
531             }
532              
533             =item * my $result=$self->Query($sql);
534              
535             =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}});
536              
537             Used to run an sql query against CPM.
538             Returns a Net::SolarWinds::Result Object: When true it contains the results, when false it contains the error.
539              
540              
541              
542             =cut
543              
544             sub Query {
545 0     0 1   my ($self,$sql)=@_;
546 0           $self->log_info("starting");
547 0           my $result;
548 0 0 0       if(ref($sql) and ref($sql) eq 'HASH') {
549 0           $self->log_info("called in post mode");
550 0           $self->log_debug(Dumper($sql));
551 0           my $path='Query';
552 0           my $request=$self->build_request('POST',$path,$sql);
553 0           $result=$self->run_request($request);
554             } else {
555 0           $self->log_info("called in get mode");
556 0           $self->log_debug("$sql");
557 0           my $path='Query?query='.uri_encode($sql);
558 0           my $request=$self->build_request('GET',$path);
559 0           $result=$self->run_request($request);
560 0           $self->log_info("stopping");
561             }
562 0           return $result;
563             }
564              
565             =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"}});
566              
567             Used to update uris in bulk, returns a Net::SolarWinds::Result object.
568              
569             =cut
570              
571             sub BulkUpdate {
572 0     0 1   my ($self,$ref)=@_;
573 0           $self->log_info("starting");
574 0           my $request=$self->build_request('POST','BulkUpdate',$ref);
575 0           my $result=$self->run_request($request);
576 0           $self->log_info("stopping");
577              
578 0           return $result
579             }
580              
581             =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"]});
582              
583             Used to delete uris in bulk, returns a Net::SolarWinds::Result object.
584              
585             =cut
586              
587             sub BulkDelete {
588 0     0 1   my ($self,$ref)=@_;
589 0           $self->log_info("starting");
590 0           my $request=$self->build_request('POST','BulkDelete',$ref);
591 0           my $result=$self->run_request($request);
592 0           $self->log_info("stopping");
593              
594 0           return $result
595             }
596              
597             =item * my $result=$self->getNodesByIp($ip);
598              
599             Find a list of nodes by a given ip.
600             Returns a Net::SolarWinds::Result Object: When true it contains an array ref of the results, when false it contains the error.
601              
602             =cut
603              
604             sub getNodesByIp {
605 0     0 1   my ($self,$ip)=@_;
606 0           $self->log_info("starting $ip");
607 0           my $query=$self->query_lookup($ip);
608 0           my $result=$self->Query($query);
609 0           $self->log_info("stopping");
610 0           return $result;
611             }
612              
613             =item * my $result=$self->getNodesByDisplayName($hostname);
614              
615             Find a list of nodes by a given hostname.
616             Returns a Net::SolarWinds::Result Object: When true it contains an array ref of the results, when false it contains the error.
617              
618             =cut
619              
620             sub getNodesByDisplayName {
621 0     0 1   my ($self,$ip)=@_;
622 0           $self->log_info("starting $ip");
623 0           my $query=$self->query_lookup($ip,$ip);
624 0           my $result=$self->Query($query);
625 0           $self->log_info("stopping");
626 0           return $result;
627             }
628              
629             =item * my $result=$self->getNodesByID($nodeid);
630              
631             Returns a Net::SolarWinds::Result object that contains a list of objects that matched that nodeid
632              
633             =cut
634              
635             sub getNodesByID {
636 0     0 1   my ($self,$id)=@_;
637 0           $self->log_info("starting");
638 0           my $query=$self->query_lookup($id);
639 0           my $result=$self->Query($query);
640              
641 0           $self->log_info("stopping");
642 0           return $result;
643             }
644              
645             =item * my $result=$self->createNode(key=>value);
646              
647             Creates a node.
648             Returns a Carter::Result Object: Retuns a data structure on sucess returns why it faield on false.
649              
650             Note, there are no presets when using this method!
651              
652             =cut
653              
654             sub nopresetsCreateNode {
655 0     0 0   my ($self,%args)=@_;
656              
657 0           $self->log_info("starting");
658             # Caption
659              
660 0           my $path='Create/Orion.Nodes';
661 0           my $request=$self->build_request('POST',$path,{%args});
662 0           my $result=$self->run_request($request);
663              
664 0 0         unless($result) {
665 0           $self->log_error("Failed to create node error was: $result");
666 0           $self->log_info("stopping");
667 0           return $result;
668             }
669 0           my $swis=$result->get_data;
670 0           $swis=~ s/(?:^"|"$)//sg;
671 0           my ($node_id)=$swis=~ /(\d+)$/s;
672              
673 0           $self->log_info("stopping");
674 0           return $self->RESULT_CLASS->new_true({Uri=>$swis,NodeID=>$node_id});
675             }
676              
677              
678             =item * my $result=$self->createNode(key=>value);
679              
680             Creates a node.
681             Returns a Carter::Result Object: Retuns a data structure on sucess returns why it faield on false.
682              
683             # the defautl key/value list is
684             qw(
685             ObjectSubType SNMP
686             EntityType Orion.Nodes
687             DynamicIP false
688             EngineID 1
689             Status 1
690             UnManaged false
691             Allow64BitCounters true
692             ObjectSubType SNMP
693             SNMPVersion 2
694             Community public
695             VendorIcon 8072.gif
696             NodeDescription Hardware
697              
698             ),
699             IOSImage=>"",
700             IOSVersion=>"",
701             Pollinterval=>60,
702             SysObjectID=>"1.3.6.1.4.1.8072.3.2.10",
703             MachineType=>"net-snmp - Linux",
704             StatCollection=>10,
705             CPULoad=>"-2",
706             MemoryUsed=>"-2",
707             PercentMemoryUsed=>"-2",
708             BufferNoMemThisHour=>"0",
709             BufferNoMemToday=>"0",
710             BufferSmMissThisHour=>"0",
711             BufferSmMissToday=>"0",
712             BufferMdMissThisHour=>"0",
713             BufferMdMissToday=>"0",
714             BufferBgMissThisHour=>"0",
715             BufferBgMissToday=>"0",
716             BufferLgMissThisHour=>"0",
717             BufferLgMissToday=>"0",
718             BufferHgMissThisHour=>"0",
719             BufferHgMissToday=>"0",
720            
721              
722             =cut
723              
724             sub createNode {
725 0     0 1   my ($self,%args)=@_;
726              
727 0           $self->log_info("starting");
728             # Caption
729 0           %args=(
730             qw(
731             ObjectSubType SNMP
732             EntityType Orion.Nodes
733             DynamicIP false
734             EngineID 1
735             Status 1
736             UnManaged false
737             Allow64BitCounters true
738             ObjectSubType SNMP
739             SNMPVersion 2
740             Community public
741             VendorIcon 8072.gif
742             NodeDescription Hardware
743              
744             ),
745             IOSImage=>"",
746             IOSVersion=>"",
747             Pollinterval=>60,
748             SysObjectID=>"1.3.6.1.4.1.8072.3.2.10",
749             MachineType=>"net-snmp - Linux",
750             StatCollection=>10,
751             CPULoad=>"-2",
752             MemoryUsed=>"-2",
753             PercentMemoryUsed=>"-2",
754             BufferNoMemThisHour=>"0",
755             BufferNoMemToday=>"0",
756             BufferSmMissThisHour=>"0",
757             BufferSmMissToday=>"0",
758             BufferMdMissThisHour=>"0",
759             BufferMdMissToday=>"0",
760             BufferBgMissThisHour=>"0",
761             BufferBgMissToday=>"0",
762             BufferLgMissThisHour=>"0",
763             BufferLgMissToday=>"0",
764             BufferHgMissThisHour=>"0",
765             BufferHgMissToday=>"0",
766             %args
767             );
768              
769 0 0         unless(exists $args{IPAddress}) {
770 0           $self->log_error("IPAddress must be set");
771 0           $self->log_info("stopping");
772 0           return $self->RESULT_CLASS->new_false("IPAddress must be set");
773             }
774              
775             # start building our required but often times missing key value pairs
776 0 0         $args{IPAddressGUID}=$self->ip_to_gui($args{IPAddress}) unless exists $args{IPAddressGUID};
777 0 0         $args{Caption}=$self->ip_to_reverse_hex($args{IPAddress}) unless exists $args{Caption};
778            
779 0           $self->log_info('stopping');
780              
781 0           return $self->nopresetsCreateNode(%args);
782             }
783             =item * my $result=$self->getNodeUri($node_id);
784              
785             When true the Net::SolarWinds::Result object contains the node uri.
786             When false it contains why it failed.
787              
788             =cut
789              
790             sub getNodeUri {
791 0     0 0   my ($self,$node_id)=@_;
792              
793 0           $self->log_info("starting");
794             #my $query="Select Uri from Orion.Nodes where NodeId=$node_id";
795 0           my $query=$self->query_lookup($node_id);
796              
797 0           my $result=$self->Query($query);
798              
799 0 0         unless($result) {
800 0           $self->log_error("could not get node uri error was: $result");
801 0           $self->log_info("stopping");
802 0           return $result;
803             }
804              
805 0 0         unless($#{$result->get_data->{results}} >-1) {
  0            
806 0           $self->log_error("NodeId: $node_id not found!");
807 0           $self->log_info("stopping");
808 0           return $self->RESULT_CLASS->new_false("NodeId: $node_id not found!")
809             }
810              
811 0           $self->log_info("stopping");
812 0           return $self->RESULT_CLASS->new_true($result->get_data->{results}->[0]->{Uri});
813              
814             }
815              
816             =item * my $result=$self->deleteSwis($uri);
817              
818             Returns a charter result object showing status.
819              
820             =cut
821              
822             sub deleteSwis {
823 0     0 1   my ($self,$uri)=@_;
824 0           $self->log_info("starting");
825 0           my $request=$self->build_request('DELETE',$uri);
826 0           my $result=$self->run_request($request);
827 0           $self->log_info("stopping");
828              
829 0           return $result;
830             }
831              
832             =item * my $result=$self->deleteNode($node_id);
833              
834             Deletes a given node.
835              
836             =cut
837              
838             sub deleteNode {
839 0     0 1   my ($self,$node_id)=@_;
840 0           my $path;
841              
842 0           $self->log_info("starting");
843 0 0         if(my $result=$self->getNodeUri($node_id)) {
844 0           $path=$result->get_data;
845             } else {
846 0           $self->log_error("Failed to delete node: $node_id error was: $result");
847 0           $self->log_info("stopping");
848 0           return $result;
849             }
850 0           my $request=$self->build_request('DELETE',$path);
851 0           my $result=$self->run_request($request);
852 0           $self->log_info("stopping");
853 0           return $result;
854             }
855              
856             =item * my $result=$self->getApplicationTemplate(@names);
857              
858             This is a wrapper for the Query interface. Returns the results that match applications by this name.
859              
860             =cut
861              
862             sub getApplicationTemplate {
863 0     0 1   my ($self,@names)=@_;
864              
865 0           $self->log_info("starting");
866 0           my $append=join ' OR ',map { sprintf q{Name='%s'},$_ } @names;
  0            
867 0           my $query=$self->query_lookup($append);
868            
869 0           my $result=$self->Query($query);
870 0           $self->log_info("stopping");
871 0           return $result;
872             }
873              
874             =item * my $result=$self->addTemplateToNode($node_id,$template_id);
875              
876             =item * my $result=$self->addTemplateToNode($node_id,$template_id,$cred_id);
877              
878             Adds a monitoring template with the default credentals to the node.
879             Returns true on success false on failure.
880              
881             =cut
882              
883             sub addTemplateToNode {
884 0     0 1   my ($self,$node_id,$template_id,$cred_id)=@_;
885 0 0         $cred_id=-4 unless defined($cred_id);
886 0           $self->log_info("starting node_id: $node_id template_id: $template_id credential_id: $cred_id");
887 0           my $request=$self->build_request(
888             'POST',
889             'Invoke/Orion.APM.Application/CreateApplication',
890             [$node_id,$template_id,$cred_id,JSON::true]
891             );
892 0           my $result=$self->run_request($request);
893 0 0         unless($result) {
894 0           $self->log_error("Failed to addTemplateToNode error was: $result");
895 0           $self->log_info("stopping");
896 0           return $result;
897             }
898              
899 0 0         if($result->get_data == -1) {
900 0           my $msg="TemplateID: $template_id all ready exists on node";
901 0           $self->log_error($msg);
902 0           $self->log_info("stopping");
903 0           return $self->RESULT_CLASS->new_false($msg);
904             }
905              
906 0           $self->log_info("stopping");
907 0           return $result;
908             }
909              
910             =item * my $result=$self->getTemplatesOnNode($node_id);
911              
912             Returns a Net::SolarWinds::Result object
913             When true it contains the templates on the node
914             when false it contains why it failed.
915              
916             =cut
917              
918             sub getTemplatesOnNode {
919 0     0 1   my ($self,$node_id)=@_;
920 0           $self->log_info("starting");
921 0           my $query=$self->query_lookup($node_id);
922 0           my $result=$self->Query($query);
923 0 0         unless($result) {
924 0           $self->log_error("failed to getTemplatesOnNode");
925 0           $self->log_info("stopping");
926 0           return $result;
927             }
928              
929 0           $self->log_info("stopping");
930 0           return $self->RESULT_CLASS->new_true($result->get_data->{results});
931             }
932              
933             =item * my $result=$self->UpdateNodeProps($nodeID,key=>values);
934              
935             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.
936              
937             =cut
938              
939             sub UpdateNodeProps {
940 0     0 1   my ($self,$nodeID,%args)=@_;
941              
942 0           $self->log_info("starting node_id: $nodeID");
943 0           my $uri='swis://localhost/Orion/Orion.Nodes/NodeID='.$nodeID;
944              
945 0           my $request;
946 0 0         if(scalar(keys(%args))==0) {
947 0           $self->log_info("called in Read mode");
948 0           $request=$self->build_request('GET',$uri);
949             } else {
950 0           $self->log_info("called in Write mode");
951 0           $request=$self->build_request('POST',$uri,{%args});
952             }
953 0           my $result=$self->run_request($request);
954 0           $self->log_info("stopping $nodeID");
955 0           return $result;
956             }
957              
958              
959             =item * my $result=$self->AddPollerToNode($nodeID,$Poller);
960              
961             Adds a poller to a node.
962              
963             =cut
964              
965              
966             sub AddPollerToNode {
967 0     0 1   my ($self,$node_id,$poller)=@_;
968              
969 0           $self->log_info("starting node_id: $node_id poller: $poller");
970 0           my $result=$self->add_poller($node_id,'N',$poller);
971 0           $self->log_info("stopping node_id: $node_id poller: $poller");
972 0           return $result;
973             }
974              
975             =item * my $result=$self->add_poller($node_id,$t,$poller)
976              
977             Returns a Net::SolarWinds::Result object when true it returns the result information that shows the results of the poller being added.
978              
979             =cut
980              
981             sub add_poller {
982 0     0 1   my ($self,$node_id,$t,$poller)=@_;
983              
984 0           $self->log_info("starting object_id: $node_id type: $t poller: $poller");
985              
986 0           my $json={
987             PollerType=>$poller,
988             NetObjectType=>$t,
989             NetObject=>$t.':'.$node_id,
990             NetObjectID=>$node_id,
991             };
992              
993 0           my $request=$self->build_request('POST','Create/Orion.Pollers',$json);
994 0           my $result=$self->run_request($request);
995 0 0         unless($result) {
996 0           $self->log_error("failed to add poller to node_id: $node_id type: $t poller: $poller error was: $result");
997 0           $self->log_info("stopping");
998 0           return $result;
999             }
1000 0           my $url=$result->get_data;
1001 0           $url=~ s/(?:^"|"$)//g;
1002              
1003 0           $self->log_info("stopping");
1004 0           return $self->RESULT_CLASS->new_true($url);
1005             }
1006              
1007             =item * my $result=$self->add_volume(key=>value);
1008              
1009             Creates a volume given the arguments passed in.
1010              
1011             Returns a Net::SolarWinds::Result object:
1012             When false it contains why it failed
1013             When true it returns a swis uri
1014              
1015             =cut
1016              
1017             sub add_volume {
1018 0     0 1   my ($self,%args)=@_;
1019              
1020 0           $self->log_info("starting");
1021 0           my $json={
1022             VolumeIndex=>2,
1023             Caption=>"/",
1024             VolumeDescription=>"/",
1025             Status=>1,
1026             VolumeType=>"Fixed Disk",
1027             VolumeTypeIcon=>"FixedDisk.gif",
1028             VolumeSpaceAvailable=>0,
1029             VolumeSize=>0,
1030             VolumePercentUsed=>0,
1031             VolumeSpaceUsed=>0,
1032             VolumeTypeID=>4,
1033             PollInterval=>240,
1034             StatCollection=>15,
1035             RediscoveryInterval=>30,
1036             ,%args
1037             };
1038              
1039 0           my $request=$self->build_request('POST','Create/Orion.Volumes',$json);
1040 0           my $result=$self->run_request($request);
1041              
1042 0           $self->log_info("stopping");
1043 0           return $result;
1044             }
1045              
1046             =item * my $result=$self->getVolumeTypeMap;
1047              
1048             Returns a Net::SolarWinds::Result Object
1049             When true Returns the volume type map.
1050             When false it returns why it failed.
1051              
1052             =cut
1053              
1054             sub getVolumeTypeMap {
1055 0     0 1   my ($self)=@_;
1056              
1057 0           $self->log_info("starting");
1058 0           my $query=$self->SWQL_getNodesByIp;
1059 0           my $result=$self->Query($query);
1060 0 0         unless($result) {
1061 0           $self->log_error("Failed to get getVolumeTypeMap error was: $result");
1062 0           $self->log_info("stopping");
1063 0           return $result;
1064             }
1065              
1066 0           my $list=$result->get_data->{results};
1067              
1068 0           my $map={};
1069 0           foreach my $type (@{$list}) {
  0            
1070 0           $map->{$type->{VolumeType}}=$type;
1071             }
1072              
1073 0           $self->log_info("stopping");
1074 0           return $self->RESULT_CLASS->new_true($map);
1075             }
1076              
1077              
1078             =item * my $result=$self->getEngines;
1079              
1080             Returns a Net::SolarWinds::Result object:
1081             When true it contains the list of poller engins.
1082             When false it contains why it failed.
1083              
1084             =cut
1085              
1086             sub getEngines {
1087 0     0 1   my ($self)=@_;
1088              
1089 0           my $result=$self->Query($self->SWQL_getEngines);
1090              
1091 0           return $result;
1092             }
1093              
1094             =item * my $result=$self->getEngine($engine);
1095              
1096             Returns a Net::SolarWinds::Result Object:
1097             When true it contains the list of matching engines.
1098             When false it cointains why it failed.
1099              
1100             Notes: if no matching engines were found the result object can be true.. but will not contain any data.
1101              
1102             =cut
1103              
1104             sub getEngine {
1105 0     0 1   my ($self,$engine)=@_;
1106              
1107 0           my $result=$self->Query($self->query_lookup($engine,$engine));
1108              
1109 0 0         return $result unless $result;
1110             }
1111             =item * my $result=$self->getVolumeMap($nodeID);
1112              
1113             Returns a Net::SolarWinds::Result object:
1114             When true it contains a hash that maps volumes to objects.
1115             When false it returns why it failed.
1116              
1117             =cut
1118              
1119             sub getVolumeMap {
1120 0     0 0   my ($self,$node_id)=@_;
1121              
1122 0           $self->log_info("starting");
1123 0           my $query=$self->query_lookup($node_id);
1124 0           my $result=$self->Query($query);
1125 0 0         unless($result) {
1126 0           $self->log_error("Failed to get getVolumeMap for node_id: $node_id error was: $result");
1127 0           $self->log_info("stopping");
1128 0           return $result;
1129             }
1130              
1131 0           my $list=$result->get_data->{results};
1132 0           my $map={};
1133              
1134             # set our max volume index to 1 if we don't have any volumes on this node
1135 0 0         my $MaxVolumeIndex=$#{$list} > -1 ? $list->[0]->{VolumeIndex} : 1;
  0            
1136              
1137 0           foreach my $vol (@{$list}) {
  0            
1138             # assume no duplicates..
1139 0           $map->{$vol->{Caption}}=$vol;
1140             }
1141              
1142 0           $self->log_info("stopping");
1143 0           return $self->RESULT_CLASS->new_true({'map'=>$map,MaxVolumeIndex=>$MaxVolumeIndex});
1144              
1145             }
1146              
1147             =item * my $result=$self->getSwisProps($uri);
1148              
1149             Returns a Net::SolarWinds::Result object:
1150             When true it the uri is set in the result hash
1151             when false the explanation as to why it failed is gven.
1152              
1153             =cut
1154              
1155             sub getSwisProps {
1156 0     0 1   my ($self,$uri)=@_;
1157 0           $self->log_info("starting");
1158 0           my $request=$self->build_request('GET',$uri);
1159 0           my $result=$self->run_request($request);
1160 0           $self->log_info("stopping");
1161 0           return $result;
1162             }
1163              
1164             =item * my $result=$self->GetNodePollers($node_id,"N|V|I");
1165              
1166             Returns a Net::SolarWinds::Result Object that contains the nodes when true when false it contains why it failed.
1167              
1168             =cut
1169              
1170             sub GetNodePollers {
1171 0     0 1   my ($self,$node_id,$type)=@_;
1172 0 0         $type='N' unless defined($type);
1173 0           $self->log_info("starting node_id: $node_id type: $type");
1174 0           my $query=$self->query_lookup($node_id,$type);
1175 0           my $result=$self->Query($query);
1176              
1177 0 0         unless($result) {
1178 0           $self->log_error("Failed to GetNodePollers on node_id: $node_id type: $type");
1179 0           $self->log_info("stopping");
1180 0           return $result;
1181             }
1182              
1183 0           my $list=$result->get_data->{results};
1184 0           my $pollers=[];
1185 0           foreach my $poller (@{$list}) {
  0            
1186 0           my $result=$self->getSwisProps('swis://localhost/Orion/Orion.Pollers/PollerID='.$poller->{PollerID});
1187 0 0         return unless $result;
1188 0           push @{$pollers},$result->get_data;
  0            
1189             }
1190 0           $self->log_info("stopping");
1191 0           return $self->RESULT_CLASS->new_true($pollers);
1192             }
1193              
1194             =item * my $result=$self->UpdateUri($uri,%args);
1195              
1196             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
1197              
1198             =cut
1199              
1200             sub UpdateUri {
1201 0     0 1   my ($self,$uri,%args)=@_;
1202              
1203 0           $self->log_info("starting Uri: $uri");
1204 0           my $request;
1205 0 0         if(scalar(keys(%args))==0) {
1206 0           $self->log_info("called in Read mode");
1207 0           $request=$self->build_request('GET',$uri);
1208             } else {
1209 0           $self->log_info("called in Write mode");
1210 0           $request=$self->build_request('POST',$uri,{%args});
1211             }
1212 0           my $result=$self->run_request($request);
1213 0           $self->log_info("stopping Uri $uri");
1214 0           return $result;
1215             }
1216              
1217             =back
1218              
1219             =head1 SEE ALSO
1220              
1221             Net::SolarWinds::REST::Batch
1222              
1223             =head1 AUTHOR
1224              
1225             Michael Shipper
1226              
1227             =head1 COPYRIGHT AND LICENSE
1228              
1229             Copyright (C) 2016 by Mike Shipper
1230              
1231             This library is free software; you can redistribute it and/or modify
1232             it under the same terms as Perl itself, either Perl version 5.10.1 or,
1233             at your option, any later version of Perl 5 you may have available.
1234              
1235             =cut
1236              
1237             1;
1238             __END__