File Coverage

blib/lib/Net/AppDynamics/REST.pm
Criterion Covered Total %
statement 53 330 16.0
branch 0 84 0.0
condition 0 3 0.0
subroutine 18 44 40.9
pod 20 23 86.9
total 91 484 18.8


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