File Coverage

blib/lib/Net/AppDynamics/REST.pm
Criterion Covered Total %
statement 50 316 15.8
branch 0 84 0.0
condition 0 3 0.0
subroutine 17 41 41.4
pod 17 21 80.9
total 84 465 18.0


line stmt bran cond sub pod time code
1             package Net::AppDynamics::REST;
2              
3 1     1   912 use Modern::Perl;
  1         2  
  1         11  
4 1     1   850 use Moo;
  1         3009  
  1         5  
5 1     1   1438 use MooX::Types::MooseLike::Base qw(:all);
  1         7839  
  1         360  
6 1     1   612 use AnyEvent::HTTP::MultiGet;
  1         133816  
  1         52  
7 1     1   1930 use JSON qw();
  1         8286  
  1         28  
8 1     1   9 use Data::Dumper;
  1         3  
  1         64  
9 1     1   6 use Carp qw(croak);
  1         3  
  1         47  
10 1     1   533 use MIME::Base64 qw();
  1         593  
  1         27  
11 1     1   8 use URI::Escape;
  1         3  
  1         65  
12 1     1   7 use HTTP::Request;
  1         2  
  1         22  
13 1     1   6 use HTTP::Headers;
  1         2  
  1         23  
14 1     1   6 use Ref::Util qw(is_plain_arrayref);
  1         4  
  1         51  
15 1     1   5 use URI::Escape;
  1         2  
  1         42  
16 1     1   7 use namespace::clean;
  1         3  
  1         9  
17              
18             BEGIN {
19 1     1   820 with 'HTTP::MultiGet::Role';
20             }
21              
22             =head1 NAME
23              
24             Net::AppDynamics::REST - AppDynamics AnyEvent Friendly REST Client
25              
26             =head1 SYNOPSIS
27              
28             use Net::AppDynamics::REST;
29             use AnyEvent;
30              
31             my $cv=AnyEvent->condvar;
32             my $obj=Net::AppDynamics::REST->new(PASS=>'password',USER=>'Username',SERVER=>'SERVERNAME');
33              
34             # to get a list of applications in a non blocking context
35             my $resut=$obj->list_applications;
36              
37             # get a list of applications in a non blocking context
38             $cv->begin;
39             $obj->que_list_applications(sub {
40             my ($self,$id,$result,$request,$response)=@_;
41             $cv->end;
42             });
43             $obj->agent->run_next;
44             $cv->recv;
45              
46             =head1 DESCRIPTION
47              
48             Appdynamics AnyEvent friendly Rest client.
49              
50             =head1 OO Declarations
51              
52             Required
53              
54             USER: Sets the user appd
55             PASS: Sets the password
56             SERVER: Sets the server
57              
58             Optional
59              
60             logger: sets the logging object
61             CUSTOMER: default customer1
62             PORT: default 8090
63             PROTO: default http
64             use_oauth: 0
65             # boolean value when set to true, the PASS option is assumed to be required for OAUTH.
66             cache_max_age: how long to keep the cache for in seconds
67             default value is 3600
68             agent: Gets/Sets the AnyEvent::HTTP::MultiGet object we will use
69             oauth_slack: 10
70             # how much slack we give oauth before we regenerate our token
71              
72             For Internal use
73              
74             data_cache: Data structure used to cache object resolion
75             cache_check: boolean value, if true a cache check is in progress
76             backlog array ref of post oauth requests to run
77             token current auth token structure
78              
79             =head2 Moo::Roles
80              
81             This module makes use of the following roles: L<HTTP::MultiGet::Role>, L<Log::LogMethods> and L<Data::Result::Moo>
82              
83             =cut
84              
85             our $VERSION = "1.007";
86              
87             has USER => (
88             is => 'ro',
89             isa => Str,
90             required => 1,
91             );
92              
93             has request_id=>(
94             isa=>Int,
95             is=>'rw',
96             default=>0,
97             );
98              
99             has cache_check => (
100             is => 'rw',
101             isa => Bool default => 0,
102             );
103              
104             has CUSTOMER => (
105             required => 1,
106             is => 'ro',
107             isa => Str,
108             default => 'customer1',
109             );
110              
111             has PASS => (
112             is => 'ro',
113             isa => Str,
114             required => 1,
115             );
116              
117             has SERVER => (
118             is => 'ro',
119             isa => Str,
120             required => 1,
121             );
122              
123             has PORT => (
124             is => 'ro',
125             isa => Int,
126             default => 8090,
127             required => 1,
128             );
129              
130             has PROTO => (
131             is => 'rw',
132             isa => Str,
133             default => 'http',
134             required => 1,
135             );
136              
137             has data_cache => (
138             is => 'rw',
139             isa => HashRef,
140             required => 1,
141             lazy => 1,
142             default => sub { { created_on => 0 } },
143             );
144              
145             has cache_max_age => (
146             is => 'ro',
147             isa => Num,
148             lazy => 1,
149             required => 1,
150             default => 3600,
151             );
152              
153             has use_oauth=>(
154             is=>'ro',
155             lazy=>1,
156             default=>0,
157             );
158              
159             has oauth_slack=>(
160             is=>'ro',
161             lazy=>1,
162             default=>10,
163             isa=>Int,
164             );
165              
166             has backlog=>(
167             isa=>ArrayRef,
168             is=>'rw',
169             default=>sub { [] },
170             );
171              
172             has token=>(
173             isa=>HashRef,
174             is=>'rw',
175             lazy=>1,
176             default=>sub { { expires=>0 } },
177             );
178              
179             # This method runs after the new constructor
180             sub BUILD {
181 1     1 0 231 my ($self) = @_;
182 1         8 my $auth = 'Basic ' . MIME::Base64::encode_base64( $self->{USER} . '@' . $self->{CUSTOMER} . ':' . $self->{PASS} );
183 1         8 $auth =~ s/\s*$//s;
184 1         8 $self->{header} = [ Authorization => $auth ];
185             }
186              
187             # this method runs before the new constructor, and can be used to change the arguments passed to the module
188             around BUILDARGS => sub {
189             my ( $org, $class, @args ) = @_;
190              
191             return $class->$org(@args);
192             };
193              
194             =head1 NonBlocking interfaces
195              
196             All methods with a prefix of que_xxx are considered non blocking interfaces.
197              
198             Default Callback arguments:
199              
200             my $code=sub {
201             # 0: this Net::AppDynamics::REST Object
202             # 1: id, for internal use
203             # 2: Data::Result Final object ( if failed, it will say why it failed )
204             # 3: HTTP::Request Last Object|undef
205             # 4: HTTP::Response Last Object|undef
206             my ($self,$id,$result,$request,$response)=@_;
207             };
208              
209             =head1 Blocking Interfaces
210              
211             All interfaces that are prefixed with que_xxx have a corisponding blocking method that is simply the xxx portion of the method name.
212              
213             Example Non Blocking version of que_list_applicatinos:
214              
215             my $result->list_applicatinos();
216              
217             When called without the que context the methods provides the more traditional blocking style inteface. When called in a blocking context only the Data::Result Object is returned.
218              
219             =head1 Application Model API
220              
221              
222             =head2 Listing Applications
223              
224             =over 4
225              
226             =item * Blocking context my $result=$self->list_applications
227              
228             Returns a Data::Result object, when true it contains the Listing of Applications, when false it contains why it failed.
229              
230             =cut
231              
232             =item * Non Blocking context my $id=$self->que_list_applicatinos($cb)
233              
234             Queues a requst to fetch the list of all applications.
235              
236             Example Callback:
237              
238             my $cb=sub {
239             my ($self,$id,$result,$request,$response)=@_;
240             # 0 Net::AppDynamics::REST Object
241             # 1 Id of the request
242             # 2 Data::Result Object
243             # 3 HTTP::Request Object
244             # 4 HTTP::Response Object
245             };
246              
247             =cut
248              
249             sub que_list_applications {
250 0     0 0 0 my ( $self, $cb ) = @_;
251 0         0 my $path = '/controller/rest/applications';
252 0         0 my $req = $self->create_get($path);
253 0         0 return $self->do_oauth_request( $req, $cb );
254             }
255              
256             =back
257              
258             =head3 Listing Tiers
259              
260             Each Application can contain many Tiers
261              
262             =over 4
263              
264             =item * Blocking context my $result=$self->list_tiers($application);
265              
266             Returns a Data::Result Object, when true it contains the Listing of Tiers
267              
268             =item * Non Blocking context my $id=$self->que_list_tiers($cb,$application);
269              
270             Queues a request to fetch the list of tiers within a given application.
271              
272             Example Callback:
273              
274             my $cb=sub {
275             my ($self,$id,$result,$request,$response)=@_;
276             # 0 Net::AppDynamics::REST Object
277             # 1 Id of the request
278             # 2 Data::Result Object
279             # 3 HTTP::Request Object
280             # 4 HTTP::Response Object
281             };
282              
283             =cut
284              
285             sub que_list_tiers {
286 0     0 1 0 my ( $self, $cb, $app ) = @_;
287 0         0 my $path = sprintf '/controller/rest/applications/%s/tiers', uri_escape($app);
288              
289 0         0 my $req = $self->create_get($path);
290 0         0 return $self->do_oauth_request( $req, $cb );
291             }
292              
293             =back
294              
295             =head4 Listing Tier Details
296              
297             =over 4
298              
299             =item * Blocking context my $result=$self->list_tier($application,$tier);
300              
301             Returns a Data::Result object, when true it contains the list of tiers.
302              
303             =item * Non BLocking Context my $id=$self->que_list_tier($cb,$application,$tier);
304              
305             Ques a request for the details of the application tier.
306              
307             Example Callback:
308              
309             my $cb=sub {
310             my ($self,$id,$result,$request,$response)=@_;
311             # 0 Net::AppDynamics::REST Object
312             # 1 Id of the request
313             # 2 Data::Result Object
314             # 3 HTTP::Request Object
315             # 4 HTTP::Response Object
316             };
317              
318             =cut
319              
320             sub que_list_tier {
321 0     0 1 0 my ( $self, $cb, $app, $tier ) = @_;
322 0         0 my $path = sprintf '/controller/rest/applications/%s/tiers/%s', uri_escape($app), uri_escape($tier);
323              
324 0         0 my $req = $self->create_get($path);
325 0         0 return $self->do_oauth_request( $req, $cb );
326             }
327              
328             =back
329              
330             =head3 Listing Busuness Transactions
331              
332             Each Application can contain many business transactions.
333              
334             =over 4
335              
336             =item * Blocking context my $result=$self->list_business_transactions($application)
337              
338             =item * Non Blocking context my $id=$self->que_list_business_transactions($cb,$application)
339              
340             Queues a request to fetch the list of business transactions for a given application
341              
342             Example Callback:
343              
344             my $cb=sub {
345             my ($self,$id,$result,$request,$response)=@_;
346             # 0 Net::AppDynamics::REST Object
347             # 1 Id of the request
348             # 2 Data::Result Object
349             # 3 HTTP::Request Object
350             # 4 HTTP::Response Object
351             };
352              
353             =cut
354              
355             sub que_list_business_transactions {
356 0     0 1 0 my ( $self, $cb, $app ) = @_;
357 0         0 my $path = sprintf '/controller/rest/applications/%s/business-transactions', uri_escape($app);
358              
359 0         0 my $req = $self->create_get($path);
360 0         0 return $self->do_oauth_request( $req, $cb );
361             }
362              
363             =back
364              
365             =head3 List Nodes
366              
367             Each Application will contain many nodes
368              
369             =over 4
370              
371             =item * Blocking context my $result=$self->list_nodes($application)
372              
373             Returns a Data::Result object, when true it contains the list of nodes.
374              
375             =item * Non Blocking context my $id=$self->que_list_nodes($cb,$application)
376              
377             Ques a request to all the nodes in a given application
378              
379             Example Callback:
380              
381             my $cb=sub {
382             my ($self,$id,$result,$request,$response)=@_;
383             # 0 Net::AppDynamics::REST Object
384             # 1 Id of the request
385             # 2 Data::Result Object
386             # 3 HTTP::Request Object
387             # 4 HTTP::Response Object
388             };
389              
390             =cut
391              
392             sub que_list_nodes {
393 0     0 1 0 my ( $self, $cb, $app ) = @_;
394 0         0 my $path = sprintf '/controller/rest/applications/%s/nodes', uri_escape($app);
395              
396 0         0 my $req = $self->create_get($path);
397 0         0 return $self->do_oauth_request( $req, $cb );
398             }
399              
400             =back
401              
402             =head3 List Tier Nodes
403              
404             Each Application Tier will contain many nodes
405              
406             =over 4
407              
408             =item * Blocking context my $result=$self->list_nodes($application,$tier)
409              
410             Returns a Data::Result object, when true it contains the list of nodes.
411              
412             =item * Non Blocking context my $id=$self->que_list_nodes($cb,$application,$tier)
413              
414             Ques a request to all the nodes in a given application
415              
416             Example Callback:
417              
418             my $cb=sub {
419             my ($self,$id,$result,$request,$response)=@_;
420             # 0 Net::AppDynamics::REST Object
421             # 1 Id of the request
422             # 2 Data::Result Object
423             # 3 HTTP::Request Object
424             # 4 HTTP::Response Object
425             };
426              
427             =cut
428              
429             sub que_list_tier_nodes {
430 0     0 0 0 my ( $self, $cb, $app,$tier ) = @_;
431 0         0 my $path = sprintf '/controller/rest/applications/%s/tiers/%s/nodes', uri_escape($app),uri_escape($tier);
432              
433 0         0 my $req = $self->create_get($path);
434 0         0 return $self->do_oauth_request( $req, $cb );
435             }
436              
437             =back
438              
439             =head4 Listing Node Details
440              
441             =over 4
442              
443             =item * Blocking context my $id=$self->list_node($application,$node)
444              
445             Returns a Data::Result object
446              
447             =item * Non BLocking context my $id=$self->que_list_node($cb,$application,$node)
448              
449             Queues a request to list the details of a node in a given tier
450              
451             Example Callback:
452              
453             my $cb=sub {
454             my ($self,$id,$result,$request,$response)=@_;
455             # 0 Net::AppDynamics::REST Object
456             # 1 Id of the request
457             # 2 Data::Result Object
458             # 3 HTTP::Request Object
459             # 4 HTTP::Response Object
460             };
461              
462             =cut
463              
464             sub que_list_node {
465 0     0 1 0 my ( $self, $cb, $app, $node ) = @_;
466 0         0 my $path = sprintf '/controller/rest/applications/%s/nodes/%s', uri_escape($app), uri_escape($node);
467              
468 0         0 my $req = $self->create_get($path);
469 0         0 return $self->do_oauth_request( $req, $cb );
470             }
471              
472             =back
473              
474             =head3 Listing BackEnds
475              
476             Each application can contain many backends
477              
478             =over 4
479              
480             =item * Non Blocking context my $id=$self->que_list_backends($cb,$application)
481              
482             Returns a Data::Result Object when true, it contains the list of backends.
483              
484             =item * Non Blocking context my $id=$self->que_list_backends($cb,$application)
485              
486             Queues a request to list the backends for a given application
487              
488             Example Callback:
489              
490             my $cb=sub {
491             my ($self,$id,$result,$request,$response)=@_;
492             # 0 Net::AppDynamics::REST Object
493             # 1 Id of the request
494             # 2 Data::Result Object
495             # 3 HTTP::Request Object
496             # 4 HTTP::Response Object
497             };
498              
499             =cut
500              
501             sub que_list_backends {
502 0     0 1 0 my ( $self, $cb, $app ) = @_;
503 0         0 my $path = sprintf '/controller/rest/applications/%s/backends', uri_escape($app);
504              
505 0         0 my $req = $self->create_get($path);
506 0         0 return $self->do_oauth_request( $req, $cb );
507             }
508              
509             =back
510              
511             =head1 Walking The entire api
512              
513             THis method walks all aspects of the appdynamics api and returns a data structure.
514              
515             The structure of $result->get_data when true contains the following anonymous hash.
516              
517             Objects are listed by ids
518              
519             ids: Anonymous hash of ids to object refrerences
520              
521             # keys used to map names to object ids
522             applications, business_transactions, tiers, nodes
523             Each element contains an anonymous hash of of an array refres
524             Each element in the array ref refres back to an ids object.
525              
526             =over 4
527              
528             =item * Blocking context my $result=$self->walk_all()
529              
530             Reutruns a Data::Result Object
531              
532             =item * Non Blocking context my $id=$self->que_walk_all($cb)
533              
534             Queues a request to walk everything.. $cb arguments are different in this caes, $cb is called with the following arguments. Keep in mind this walks every single object in mass and up to 20 requests are run at a time ( by default ), so this can put a strain on your controler if run too often.
535              
536             my $cb=sub {
537             my ($self,$id,$result,$request,$response,$method,$application)=@_;
538             # 0: this Net::AppDynamics::REST Object
539             # 1: id, for internal use
540             # 2: Data::Result Final object ( if failed, it will say why it failed )
541             # 3: HTTP::Request Last Object|undef
542             # 4: HTTP::Response Last Object|undef
543             # 5: method ( wich method this result set is for )
544             # 6: application ( undef the method is list_applications )
545             };
546              
547             =cut
548              
549             sub que_walk_all {
550 0     0 1 0 my ( $self, $cb ) = @_;
551              
552 0         0 my $state = 1;
553 0         0 my $data = {};
554 0         0 my $total = 0;
555 0         0 my @ids;
556              
557             my $app_cb = sub {
558 0     0   0 my ( $self, $id, $result, $request, $response ) = @_;
559              
560 0 0       0 if ($result) {
561 0         0 foreach my $obj ( @{ $result->get_data } ) {
  0         0  
562 0         0 $data->{ids}->{ $obj->{id} } = $obj;
563 0         0 $obj->{applicationId} = $obj->{id};
564 0         0 $obj->{applicationName} = $obj->{name};
565 0         0 my $app_id = $obj->{id};
566 0         0 $obj->{our_type} = 'applications';
567 0         0 my $name = lc( $obj->{name} );
568 0 0       0 $data->{applications}->{ lc( $obj->{name} ) } = [] unless exists $data->{applications}->{ $obj->{name} };
569 0         0 push @{ $data->{applications}->{$name} }, $obj->{id};
  0         0  
570              
571 0         0 foreach my $method (qw(que_list_nodes que_list_tiers que_list_business_transactions )) {
572 0         0 ++$total;
573             my $code = sub {
574 0         0 my ( $self, undef, $result, $request, $response ) = @_;
575 0 0       0 return unless $state;
576 0 0       0 return ( $cb->( $self, $id, $result, $request, $response, $method, $obj ), $state = 0 ) unless $result;
577 0         0 --$total;
578 0         0 foreach my $sub_obj ( @{ $result->get_data } ) {
  0         0  
579 0         0 my $target = $method;
580 0         0 $target =~ s/^que_list_//;
581              
582 0         0 foreach my $field (qw(name machineName)) {
583 0 0       0 next unless exists $sub_obj->{$field};
584 0         0 my $name = lc( $sub_obj->{$field} );
585 0 0       0 $data->{$target}->{$name} = [] unless exists $data->{$target}->{$name};
586 0         0 push @{ $data->{$target}->{$name} }, $sub_obj->{id};
  0         0  
587             }
588 0         0 $sub_obj->{applicationId} = $obj->{id};
589 0         0 $sub_obj->{applicationName} = $obj->{name};
590 0         0 $sub_obj->{our_type} = $target;
591 0         0 $data->{ids}->{ $sub_obj->{id} } = $sub_obj;
592 0 0       0 if ( exists $sub_obj->{machineId} ) {
593 0         0 $data->{ids}->{ $sub_obj->{machineId} } = $sub_obj;
594 0         0 $data->{id_map}->{$app_id}->{ $sub_obj->{machineId} }++;
595             }
596 0         0 $data->{id_map}->{$app_id}->{ $sub_obj->{id} }++;
597 0 0       0 if ( exists $sub_obj->{tierId} ) {
598 0         0 $data->{id_map}->{ $sub_obj->{tierId} }->{ $sub_obj->{id} }++;
599 0 0       0 $data->{id_map}->{ $sub_obj->{tierId} }->{ $sub_obj->{machineId} }++ if exists $sub_obj->{machineId};
600             }
601             }
602              
603 0 0       0 if ( $total == 0 ) {
604 0         0 return ( $cb->( $self, $id, $self->new_true($data), $request, $response, 'que_walk_all', $obj ),
605             $state = 0 );
606             }
607 0         0 };
608 0         0 push @ids, $self->$method( $code, $obj->{id} );
609             }
610             }
611             } else {
612 0         0 return $cb->( $self, $id, $result, $request, $response, 'que_list_applications', undef );
613             }
614 0         0 $self->add_ids_for_blocking(@ids);
615 0         0 $self->agent->run_next;
616 0         0 };
617              
618 0         0 return $self->que_list_applications($app_cb);
619             }
620              
621             =back
622              
623             =head1 Alert and Response API
624              
625             Queues a health rule violation lookup
626              
627             For more details, please see: L<https://docs.appdynamics.com/display/PRO43/Alert+and+Respond+API#AlertandRespondAPI-RetrieveAllHealthRuleViolationsinaBusinessApplication>
628              
629             =over 4
630              
631             =item * Blocking context my $result=$self->health_rule_violations($app,%args);
632              
633             Example ( defaults if no arguments are passed ):
634              
635             my $result=$self->health_rule_violations($cb,"PRODUCTION",'time-range-type'=>'BEFORE_NOW','duration-in-mins'=>15);
636              
637             =item * Non Blocking context my $id=$self->que_health_rule_violations($cb,$app,%args);
638              
639             Example ( defaults if no arguments are passed ):
640              
641             my $id=$self->que_health_rule_violations($cb,"PRODUCTION",'time-range-type'=>'BEFORE_NOW','duration-in-mins'=>15);
642              
643             Example Callback:
644              
645             my $cb=sub {
646             my ($self,$id,$result,$request,$response)=@_;
647             # 0 Net::AppDynamics::REST Object
648             # 1 Id of the request
649             # 2 Data::Result Object
650             # 3 HTTP::Request Object
651             # 4 HTTP::Response Object
652             };
653              
654             =cut
655              
656             sub que_health_rule_violations {
657 0     0 1 0 my ( $self, $cb, $app, %args ) = @_;
658 0 0       0 $app = "PRODUCTION" unless defined($app);
659 0         0 my $path = sprintf '/controller/rest/applications/%s/problems/healthrule-violations', uri_escape($app);
660 0 0       0 if ( keys %args == 0 ) {
661 0         0 %args = ( 'time-range-type' => 'BEFORE_NOW', 'duration-in-mins' => 15 );
662             }
663              
664 0         0 my $req = $self->create_get( $path, %args );
665 0         0 return $self->do_oauth_request( $req, $cb );
666             }
667              
668             =back
669              
670             =head1 Configuration Import and Export API
671              
672             This section documents the Configuration Import and Export API.
673              
674             =over 4
675              
676             =item * Blocking context my $result=$self->export_policies($app)
677              
678             =item * Non Blocking context my $id=$self->que_export_policies($cb,$app)
679              
680             Queues the exporting of a policy
681              
682             Example Callback:
683              
684             my $cb=sub {
685             my ($self,$id,$result,$request,$response)=@_;
686             # 0 Net::AppDynamics::REST Object
687             # 1 Id of the request
688             # 2 Data::Result Object
689             # 3 HTTP::Request Object
690             # 4 HTTP::Response Object
691             };
692              
693             =cut
694              
695             sub que_export_policies {
696 0     0 1 0 my ( $self, $cb, $app ) = @_;
697 0         0 my $path = sprintf '/controller/policies/%s', uri_escape($app);
698              
699 0         0 my $req = $self->create_get($path);
700 0         0 return $self->do_oauth_request( $req, $cb );
701             }
702              
703             =back
704              
705             =head1 Finding Health rule violations
706              
707             See: que_health_rule_violations and que_resolve for more information.
708              
709             =over 4
710              
711             =item * Blocking Context my $result=$self->find_health_rule_violations($type,$name)
712              
713             Returns a Data::Result Object, when true the result will cointain health rules on anything that resolved.
714              
715             =item * Non Blocking Context my $id=$self->que_find_health_rule_violations($cb,$type,$name)
716              
717             =cut
718              
719             sub que_find_health_rule_violations {
720 0     0 1 0 my ( $self, $cb, $type, $name ) = @_;
721              
722 0         0 my $id;
723             my $code = sub {
724 0     0   0 my ( $self, undef, $result, $request, $response ) = @_;
725 0 0       0 return $cb->(@_) unless $result;
726 0         0 my @resolved = @{ $result->get_data };
  0         0  
727              
728 0         0 my @ids;
729 0         0 my $resolved = {};
730 0         0 my $state = 1;
731 0         0 my $alerts = [];
732 0         0 my $total = 0;
733 0         0 my $apps = {};
734              
735             # safe to use here, since we know it is current
736 0         0 my $cache = $self->data_cache;
737              
738             my $sub_cb = sub {
739 0         0 my ( $self, undef, $result, $request, $response ) = @_;
740 0 0       0 return unless $state;
741 0 0       0 unless ($result) {
742 0         0 $cb->(@_);
743 0         0 $state = 0;
744 0         0 return;
745             }
746 0         0 LOOK_UP: foreach my $event ( @{ $result->get_data } ) {
  0         0  
747 0         0 my $entity_id = $event->{affectedEntityDefinition}->{entityId};
748              
749 0 0       0 next unless exists $resolved->{$entity_id};
750 0         0 my $target = $cache->{ids}->{$entity_id};
751 0         0 foreach my $obj (@resolved) {
752 0         0 my $type = $obj->{our_type};
753 0 0       0 if ( $type eq 'tiers' ) {
    0          
    0          
    0          
754 0         0 my $tier_id = $obj->{id};
755 0 0       0 next unless exists $target->{tierId};
756 0 0       0 next unless $target->{tierId} == $tier_id;
757 0         0 push @{$alerts}, $event;
  0         0  
758             } elsif ( $type eq 'applications' ) {
759 0         0 my $app_id = $obj->{id};
760 0 0       0 next unless $target->{applicationId} == $app_id;
761 0         0 push @{$alerts}, $event;
  0         0  
762             } elsif ( $type eq 'business_transactions' ) {
763 0         0 my $id = $obj->{id};
764 0 0       0 next unless $target->{id} == $id;
765 0         0 push @{$alerts}, $event;
  0         0  
766             } elsif ( $type eq 'nodes' ) {
767 0         0 foreach my $key (qw(id machineId)) {
768 0 0       0 next unless exists $obj->{$key};
769 0 0       0 next unless exists $target->{$key};
770 0 0       0 next unless $obj->{$key} == $target->{$key};
771 0         0 push @{$alerts}, $event;
  0         0  
772 0         0 next LOOK_UP;
773             }
774             }
775             }
776             }
777              
778 0 0       0 return unless --$total == 0;
779 0         0 $cb->( $self, $id, $self->new_true($alerts), undef, undef );
780 0         0 };
781 0         0 foreach my $obj ( @{ $result->get_data } ) {
  0         0  
782 0         0 $apps->{ $obj->{applicationId} }++;
783              
784 0         0 foreach my $key (qw(id applicationId tierId machineId)) {
785 0 0       0 next unless exists $obj->{$key};
786 0         0 $resolved->{ $obj->{$key} }++;
787 0         0 my $id = $obj->{$key};
788 0 0       0 if ( exists $cache->{id_map}->{$id} ) {
789 0         0 my @keys = keys %{ $cache->{id_map}->{$id} };
  0         0  
790 0         0 @{$resolved}{@keys} = @{ $cache->{id_map}->{$id} }{@keys};
  0         0  
  0         0  
791             }
792             }
793 0         0 ++$total;
794              
795 0         0 my $app_id = $obj->{applicationId};
796 0         0 push @ids, $self->que_health_rule_violations( $sub_cb, $app_id );
797             }
798 0         0 $self->add_ids_for_blocking(@ids);
799 0         0 $self->agent->run_next;
800 0         0 };
801              
802 0         0 $id = $self->que_resolve( $code, $type, $name );
803 0         0 return $id;
804             }
805              
806             =back
807              
808             =head1 Listing Metrics
809              
810             =head2 Getting Metrics for an Application
811              
812             =over 4
813              
814             =item * Non Blocking my $result=$self->que_get_application_metric($cb,$application,,%args);
815              
816             Queues a request to fetch a given metric
817              
818             Example Callback:
819              
820             my $cb=sub {
821             my ($self,$id,$result,$request,$response)=@_;
822             # 0 Net::AppDynamics::REST Object
823             # 1 Id of the request
824             # 2 Data::Result Object
825             # 3 HTTP::Request Object
826             # 4 HTTP::Response Object
827             };
828              
829             =item * Blocking my $result=$self->get_application_metric($application,,%args);
830              
831             In a blocking context, $result contains the results when true and why it failed when false.
832              
833             =back
834              
835             =cut
836              
837             sub que_get_application_metric {
838 0     0 1 0 my ( $self, $cb, $app, @args ) = @_;
839              
840 0         0 my $path = '/controller/rest/applications/' . $app . '/metric-data';
841 0         0 my $get = $self->create_get( $path, @args );
842 0         0 return $self->do_oauth_request( $get, $cb );
843             }
844              
845              
846             =head1 Resolving Objects
847              
848             Used to resolve tiers, nodes, business_transactions, and applications to thier application's id.
849              
850             cb: standard callback
851             type: String representing the typpe of object to resolve (tiers|nodes|business_transactions|applications);
852             name: name to be resolved
853              
854             Uses the internal cache to resolve the object, if the internal cache is out of date or empty the cache will be refreshed.
855              
856             =over 4
857              
858             =item * Blocking context my $result=$self->resolve($type,$name);
859              
860             Returns a Data::Result object, when true it contains the resolved object.
861              
862             =item * Non Blocking context my $id=$self->que_resolve($cb,$type,$name);
863              
864             Example Callback:
865              
866             my $cb=sub {
867             my ($self,$id,$result,$request,$response)=@_;
868             # 0 Net::AppDynamics::REST Object
869             # 1 Id of the request
870             # 2 Data::Result Object
871             # 3 HTTP::Request Object
872             # 4 HTTP::Response Object
873             };
874              
875             =cut
876              
877             sub que_resolve {
878 0     0 1 0 my ( $self, $cb, $type, $name ) = @_;
879              
880             my $code = sub {
881 0     0   0 my ( $self, $id, $result, $request, $response ) = @_;
882 0 0       0 return $cb->(@_) unless $result;
883              
884 0         0 foreach my $key ( $type, $name ) {
885 0         0 $key = lc($key);
886 0         0 $key =~ s/(?:^\s+|\s+$)//sg;
887             }
888              
889 0         0 my $cache = $result->get_data;
890 0 0       0 if ( exists $cache->{$type} ) {
891 0 0       0 if ( exists( $cache->{$type}->{$name} ) ) {
892 0         0 my $data = [];
893 0         0 foreach my $target ( @{ $cache->{$type}->{$name} } ) {
  0         0  
894 0         0 push @{$data}, $cache->{ids}->{$target};
  0         0  
895             }
896             return $cb->( $self, $id, $self->new_false("Type: [$type] Name: [$name] Not Found"), undef, undef )
897 0 0       0 if $#{$data} == -1;
  0         0  
898 0         0 $cb->( $self, $id, $self->new_true($data), $request, $response );
899             } else {
900 0         0 $cb->( $self, $id, $self->new_false("Type: [$type] Name: [$name] Not Found"), undef, undef );
901             }
902             } else {
903 0         0 $cb->( $self, $id, $self->new_false("Type: [$type] Name: [$name] Not Found"), undef, undef );
904             }
905 0         0 };
906 0         0 my $id = $self->que_check_cache($code);
907 0         0 return $id;
908             }
909              
910             =back
911              
912             =head1 Internal Caching
913              
914             The Net::AppDynamics::REST object uses an internal cache for resolving objects. The $forceCacheRefresh is a boolean value, when set to true it forces the cache to refresh reguardless of the age of the cache.
915              
916             =over 4
917              
918             =item * Non BLocking context my $result=$self->que_check_cache($cb,$forceCacheRefresh);
919              
920             Returns a Data::Result object, when true it contains the cache.
921              
922             =item * BLocking context my $id=$self->que_check_cache($cb,$forceCacheRefresh);
923              
924             Queues a cache check. The resolve cache is refreshed if it is too old.
925              
926             Example Callback:
927              
928             my $cb=sub {
929             my ($self,$id,$result,$request,$response)=@_;
930             # 0 Net::AppDynamics::REST Object
931             # 1 Id of the request
932             # 2 Data::Result Object
933             # 3 HTTP::Request Object
934             # 4 HTTP::Response Object
935             };
936              
937             =cut
938              
939             sub que_check_cache {
940 0     0 1 0 my ( $self, $cb, $force ) = @_;
941              
942 0         0 my $max = time - $self->cache_max_age;
943 0 0 0     0 if ( !$force and $self->data_cache->{created_on} > $max ) {
944 0         0 return $self->queue_result( $cb, $self->new_true( $self->data_cache ) );
945             } else {
946 0         0 $self->cache_check(1);
947             return $self->que_walk_all(
948             sub {
949 0     0   0 my ( $self, $id, $result, @list ) = @_;
950 0         0 $self->cache_check(0);
951 0 0       0 return $cb->(@_) unless $result;
952 0         0 $self->data_cache( $result->get_data );
953 0         0 $self->data_cache->{created_on} = time;
954 0         0 return $cb->( $self, $id, $result, @list );
955             }
956 0         0 );
957             }
958             }
959              
960             =back
961              
962             =head1 OO Inernal OO Methods
963              
964             =over 4
965              
966             =item * my $url=$self->base_url
967              
968             Creates the base url for a request.
969              
970             =cut
971              
972             sub base_url {
973 1     1 1 454 my ($self) = @_;
974 1         25 my $url = $self->PROTO . '://' . $self->SERVER . ':' . $self->PORT;
975 1         28 return $url;
976             }
977              
978             =item * my $request=$self->create_get($path,%args);
979              
980             Create a request object for $path with the required arguments
981              
982             =cut
983              
984             sub create_get {
985 0     0 1   my ( $self, $path, @args ) = @_;
986              
987 0           my $str = $self->base_url . $path . '?';
988 0           push @args, 'output', 'JSON';
989              
990 0           my $count = 0;
991 0           while ( my ( $key, $value ) = splice @args, 0, 2 ) {
992 0 0         if ( $count++ == 0 ) {
993 0           $str .= "$key=" . uri_escape($value);
994             } else {
995 0           $str .= "\&$key=" . uri_escape($value);
996             }
997             }
998              
999            
1000 0           my $headers = HTTP::Headers->new( @{ $self->{header} } );
  0            
1001 0           my $request = HTTP::Request->new( GET => $str, $headers );
1002              
1003 0           return $request;
1004             }
1005              
1006             =item * my $request=$self->que_setup_token($cb)
1007              
1008             Runs a non blocking oauth request
1009              
1010             my ($self,$id,$result,$request,$response)=@_;
1011             # 0 Net::AppDynamics::REST Object
1012             # 1 Id of the request
1013             # 2 Data::Result Object
1014             # 3 HTTP::Request Object
1015             # 4 HTTP::Response Object
1016              
1017             =item * my $result=$self->setup_token()
1018              
1019             Runs a blocking oatuh request, reutrns a Data::Result object.
1020              
1021             =cut
1022              
1023             sub que_setup_token {
1024 0     0 1   my ($self,$cb)=@_;
1025            
1026 0           my $headers = HTTP::Headers->new();
1027 0           $headers->header('Content-Type','application/vnd.appd.cntrl+protobuf;v=1');
1028             my $content=sprintf 'grant_type=client_credentials&client_id=%s@%s&client_secret=%s',
1029 0           map { uri_escape($_) } $self->USER,$self->CUSTOMER,$self->PASS;
  0            
1030 0           my $req=HTTP::Request->new('POST'=>$self->base_url.'/controller/api/oauth/access_token',$headers,$content);
1031            
1032 0           return $self->queue_request( $req, $cb);
1033             }
1034              
1035              
1036             =item * \&handle_token_setup
1037              
1038             A Hard code ref used to handle setting up of oauth tokens
1039              
1040             =cut
1041              
1042             sub handle_token_setup {
1043 0     0 0   my ($self,$id,$result,$request,$response)=@_;
1044 0           delete $self->{_do_oauth};
1045              
1046 0 0         unless($result) {
1047 0           foreach my $set (@{$self->backlog}) {
  0            
1048 0           my ($req,$cb)=@$set;
1049 0           eval { $cb->(@_) };
  0            
1050 0 0         $self->log_error("Failed to run callback, error was: $@") if $@;
1051             }
1052             } else {
1053 0           my $data=$result->get_data;
1054 0           $data->{expires}=time + $data->{expires_in} - $self->oauth_slack;
1055 0           $self->token($data);
1056 0           $self->{header}=['Authorization','Bearer '.$data->{access_token}];
1057 0           my @ids;
1058 0           my $count=0;
1059 0           foreach my $set (@{$self->backlog}) {
  0            
1060 0           my ($req,$cb)=@$set;
1061 0           my $headers = HTTP::Headers->new( @{ $self->{header} } );
  0            
1062 0           my $request = HTTP::Request->new( $req->method=> $req->uri, $headers,$req->content );
1063 0           my $id=$self->queue_request($request,$cb);
1064 0           push @ids,$id;
1065             }
1066 0           @{$self->backlog}=();
  0            
1067 0           $self->add_ids_for_blocking(@ids);
1068 0           $self->agent->run_next;
1069             }
1070             }
1071              
1072             =item * $self->do_oauth_request($req,$cb)
1073              
1074             Handles the added logic for dealing with blocking and non blocking when oauth mode is inabled.
1075              
1076             =cut
1077              
1078             sub do_oauth_request {
1079 0     0 1   my ($self,$req,$cb)=@_;
1080              
1081             # stop here and run like we always have when using oauth
1082 0 0         return $self->queue_request($req,$cb) unless $self->use_oauth;
1083              
1084              
1085 0 0         if($self->token->{expires}<=time) {
1086 0           my $id=$self->agent->false_id($self->agent->false_id -1);
1087             my $code=sub {
1088 0     0     my ($self,$real_id,$result,$req,$res)=@_;
1089 0           $cb->($self,$id,$result,$req,$res);
1090 0           };
1091              
1092 0           push @{$self->backlog},[$req,$code];
  0            
1093 0 0         return $id if $self->{_do_oauth};
1094              
1095 0           $self->que_setup_token(\&handle_token_setup);
1096 0           $self->add_ids_for_blocking($id);
1097              
1098 0           return $id;
1099             } else {
1100 0           return $self->queue_request($req,$cb);
1101             }
1102             }
1103              
1104             =back
1105              
1106             =head1 Bugs and Patches
1107              
1108             Please report bugs and submit patches via L<https://rt.cpan.org>
1109              
1110             =head2 Todo
1111              
1112             Implement more of the api.. it is pretty extensive, patches welcome!
1113              
1114             =head1 See Also
1115              
1116             L<https://docs.appdynamics.com/display/PRO43/AppDynamics+APIs>
1117              
1118             L<AnyEvent::HTTP::MultiGet>
1119              
1120             =head1 AUTHOR
1121              
1122             Michael Shipper L<mailto:AKALINUX@CPAN.ORG>
1123              
1124             =cut
1125              
1126             1;