File Coverage

blib/lib/WebService/Amazon/Support.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


line stmt bran cond sub pod time code
1             package WebService::Amazon::Support;
2 1     1   15048 use base qw( WebService::Simple );
  1         2  
  1         498  
3              
4             use 5.006;
5             use strict;
6             use warnings;
7              
8             use AWS::Signature4;
9             use Carp;
10             use HTTP::Request::Common;
11             use JSON;
12             use LWP;
13             use Params::Validate qw( :all );
14             use Readonly;
15             #use Smart::Comments '###';
16             #use Smart::Comments '###', '####';
17             #use Smart::Comments '###', '####', '#####';
18              
19             =encoding utf-8
20              
21             =head1 NAME
22              
23             WebService::Amazon::Support - The great new WebService::Amazon::Support!
24              
25             =head1 VERSION
26              
27             Version 0.0.4
28              
29             =cut
30              
31             use version;
32             our $VERSION = version->declare("v0.0.4");
33              
34             =head1 SYNOPSIS
35              
36             This module provides a Perl wrapper around Amazon's Support API
37             ( L ). You will need
38             to be an AWS customer with an ID and Secret which has been provided
39             access to Support.
40              
41             B Some parameter validation is purposely lax. The API will
42             generally fail when invalid params are passed. The errors may not
43             be helpful.
44              
45             use WebService::Amazon::Support;
46              
47             my $sup = WebService::Amazon::Support->new( param => { id => $AWS_ACCESS_KEY_ID,
48             secret => $AWS_ACCESS_KEY_SECRET } );
49             ...
50              
51             =cut
52              
53             # From: http://docs.aws.amazon.com/general/latest/gr/rande.html#awssupport_region
54             # FIXME: use an array and assemble the URL in the constructor?
55             Readonly our %REGIONS => ( 'us-east-1' => 'https://support.us-east-1.amazonaws.com' );
56              
57             # Global API Version and Default Region
58             Readonly our $API_VERSION => '2013-04-15';
59             Readonly our $DEF_REGION => 'us-east-1';
60             Readonly our $DEF_LANG => 'en';
61             Readonly our $TARGET_PRE => 'AWSSupport_20130415';
62              
63             # some defaults
64             __PACKAGE__->config(
65             base_url => $REGIONS{'us-east-1'},
66             );
67              
68             # Global patterns for param validation
69             Readonly our $REGEX_ID => '^[A-Z0-9]{20}$';
70             Readonly our $REGEX_REGION => '^[a-z]{2}-[a-z].*?-\d$';
71             Readonly our $REGEX_SECRET => '^[A-Za-z0-9/+]{40}$';
72              
73             =head1 INTERFACE
74              
75             =head2 new
76              
77             Inherited from L, and takes all the same arguments.
78             You B provide the Amazon required arguments of B, and B
79             in the param hash:
80              
81             my $sup = WebService::Amazon::Support->new( param => { id => $AWS_ACCESS_KEY_ID,
82             secret => $AWS_ACCESS_KEY_SECRET } );
83              
84             =over 4
85              
86             =item B
87              
88             =item id B<(required)>
89              
90             You can find more information in the AWS docs:
91             L
92              
93             =item secret B<(required)>
94              
95             You can find more information in the AWS docs:
96             L
97              
98             =back
99              
100             =cut
101              
102             # HASH to hold API call specifications
103             our( %API_SPEC );
104              
105             # #################################################################################################
106             #
107             # Override WebService::Simple methods
108             #
109              
110             $API_SPEC{'new'} = {
111             id => { type => SCALAR, regex => qr/$REGEX_ID/, },
112             region => { type => SCALAR, regex => qr/$REGEX_REGION/, optional => 1, default => $DEF_REGION, },
113             secret => { type => SCALAR, regex => qr/$REGEX_SECRET/, },
114             };
115              
116             # Override valid options, set API version and create XML parser
117             sub new {
118             ### Enter: (caller(0))[3]
119             my( $class, %args ) = @_;
120             my $self = $class->SUPER::new(%args);
121            
122             # this is silly, but easier for validation
123             my( @temp_params ) = %{ $self->{basic_params} };
124             my %params = validate( @temp_params, $API_SPEC{'new'} );
125             ##### %params
126            
127             # set our API version
128             $self->{api_version} = $API_VERSION;
129            
130             # for parsing the responses
131             $self->{js} = JSON->new->allow_nonref;
132            
133             # store a request signer for later
134             $self->{signer} = AWS::Signature4->new( -access_key => $self->{basic_params}{id},
135             -secret_key => $self->{basic_params}{secret} );
136              
137             # store a user agent for later
138             $self->{ua} = LWP::UserAgent->new( agent => "$class/$VERSION" );
139            
140             # change the endpoint for the requested region
141             if ( $params{region} && $REGIONS{$params{region}} ) {
142             $self->{base_url} = $REGIONS{$params{region}};
143             }
144             elsif ( $params{region} && !$REGIONS{$params{region}} ) {
145             carp( "Unknown region: $params{region}; using $DEF_REGION...")
146             }
147             ### Exit: (caller(0))[3]
148             return bless($self, $class);
149             }
150              
151             # override parent get to perform the required AWS signatures
152             sub _get {
153             ### Enter: (caller(0))[3]
154             my( $self ) = shift;
155             my( %args ) = @_;
156             #my $self = $class->SUPER::new(%args);
157            
158             ##### $self
159             my $signer = AWS::Signature4->new( -access_key => $self->{basic_params}{id},
160             -secret_key => $self->{basic_params}{secret} );
161              
162             my $ua = LWP::UserAgent->new();
163              
164             ### %args
165             if ( !$args{params} ) {
166             carp( "No paramerter provided for request!" );
167             return undef;
168             }
169             else {
170             $args{params}{Version} = $self->{api_version};
171             }
172              
173             my $uri = URI->new( $self->{base_url} );
174             $uri->query_form( $args{params} );
175             #### $uri
176              
177             my $url = $signer->signed_url($uri); # This gives a signed URL that can be fetched by a browser
178             #### $url
179             # This doesn't quite work (it wants path and args onyl)
180             #my $response = $self->SUPER::get( $url );
181             my $response = $ua->get($url);
182             ##### $response
183             if ( $response->is_success ) {
184             ### Exit: (caller(0))[3]
185             return $self->{xs}->XMLin( $response->decoded_content );
186             }
187             else {
188             carp( $response->status_line );
189             ### Exit: (caller(0))[3]
190             return undef;
191             }
192             ### Exit: (caller(0))[3]
193             }
194              
195             # override parent post to perform the required AWS signatures
196             sub _post {
197             my( $self, %args ) = @_;
198              
199             ### %args
200             if ( !$args{params} ) {
201             carp( "No paramerter provided for request!" );
202             return undef;
203             }
204             else {
205             $args{params}{Version} = $self->{api_version};
206             }
207            
208             # JSON encode the params
209             my( $js ) = $self->{js}->encode( $args{params} );
210             ### $js
211            
212             # set custom HTTP request header fields
213             my $req = HTTP::Request->new( POST => $self->{base_url} );
214             #
215             # NOTE: Shenanigans! Reverse engineered from https://github.com/boto/boto/blob/develop/boto/support/layer1.py#L652
216             #
217             $req->header( 'X-Amz-Target' => join( '.', $TARGET_PRE, $args{params}{Action} ) );
218             $req->header( 'content-type' => 'application/x-amz-json-1.1' );
219            
220             $req->content( $js );
221             ### $req
222              
223             $self->{signer}->sign($req);
224             #### $req
225             my $response = $self->{ua}->request( $req );
226             ##### $response
227             my( $jsDecode ) = $self->{js}->decode( $response->decoded_content );
228             if ( $response->is_success ) {
229             return $jsDecode;
230             }
231             else {
232             carp( $self->{js}->pretty->encode( $jsDecode ) . $response->status_line );
233             return undef;
234             }
235             }
236              
237             # implement a general way to configure repeated options to match the API
238             sub _handleRepeatedOptions {
239             ### Enter: (caller(0))[3]
240             my( $self ) = shift;
241             my( $repeat, %params ) = @_;
242             #### Start: %params
243              
244             if ( $params{$repeat} && ref( $params{$repeat} ) eq "ARRAY" ) {
245             my( $i ) = 1;
246             foreach my $t ( @{ $params{$repeat} } ) {
247             $params{"${repeat}.member.${i}"} = $t;
248             $i++;
249             }
250             delete( $params{$repeat} );
251             }
252            
253             #### End: %params
254             ### Exit: (caller(0))[3]
255             return %params;
256             }
257              
258             # most of the calls can do this
259             sub _genericCallHandler {
260             ### Enter: (caller(0))[3]
261             my( $op ) = (split( /::/, (caller(1))[3] ))[-1];
262             ### Operation: $op
263              
264             my( $self ) = shift;
265             my %params = validate( @_, $API_SPEC{$op} );
266             $params{Action} = $op;
267             ### %params
268            
269             # handle ARRAY / repeated options -- this API is JSON: don't do anything
270             # foreach my $opt ( keys( %{ $API_SPEC{$op} } ) ) {
271             # ### Checking opt: $opt
272             # if ( $API_SPEC{$op}->{$opt}->{type} == ARRAYREF ) {
273             # ### Found a repeatable option: $opt
274             # ( %params ) = $self->_handleRepeatedOptions( $opt, %params );
275             # }
276             # }
277            
278             ### %params
279             my( $rez ) = $self->_post( params => \%params );
280             ### Exit: (caller(0))[3]
281             return $rez;
282             }
283              
284             # #################################################################################################
285             #
286             # API Methods Below
287             #
288              
289             # #################################################################################################
290             ## AddAttachmentsToSet
291              
292             =head2 AddAttachmentsToSet( )
293              
294             Unimplimented (for now)
295              
296             =cut
297              
298             # #################################################################################################
299             ## AddCommunicationToCase
300              
301             =head2 AddCommunicationToCase( )
302              
303             Unimplimented (for now)
304              
305             =cut
306              
307             # #################################################################################################
308             ## CreateCase
309              
310             =head2 CreateCase( )
311              
312             Unimplimented (for now)
313              
314             =cut
315              
316             # #################################################################################################
317             ## DescribeAttachment
318              
319             =head2 DescribeAttachment( )
320              
321             Returns the attachment that has the specified ID. Attachment IDs are
322             generated by the case management system when you add an attachment to
323             a case or case communication. Attachment IDs are returned in the
324             AttachmentDetails objects that are returned by the
325             DescribeCommunications operation.
326              
327             Refer to L
328              
329             =over 4
330              
331             =item B
332              
333             =item attachmentId B<(required string)>
334              
335             The ID of the attachment to return. Attachment IDs are returned by the DescribeCommunications operation.
336              
337             =item B
338              
339             =back
340              
341             =cut
342              
343             $API_SPEC{'DescribeAttachment'} = {
344             attachmentId => { type => SCALAR },
345             };
346              
347             sub DescribeAttachment {
348             ### Enter: (caller(0))[3]
349             my( $rez ) = _genericCallHandler( @_ );
350             ### Exit: (caller(0))[3]
351             return $rez;
352             }
353              
354             # #################################################################################################
355             ## DescribeCases
356              
357             =head2 DescribeCases( )
358              
359             Unimplimented (for now)
360              
361             =cut
362              
363             # #################################################################################################
364             ## DescribeCommunications
365              
366             =head2 DescribeCommunications( )
367              
368             Unimplimented (for now)
369              
370             =cut
371              
372             # #################################################################################################
373             ## DescribeServices
374              
375             =head2 DescribeServices( )
376              
377             Returns a list of the available solution stack names.
378              
379             Refer to L
380              
381             =over 4
382              
383             =item B
384              
385             =item Language I<(optional string)>
386              
387             The ISO 639-1 code for the language in which AWS provides support. AWS
388             Support currently supports English ("en") and Japanese ("ja"). Language
389             parameters must be passed explicitly for operations that take them.
390              
391             =item ServiceCodeList I<(optional array)>
392              
393             A JSON-formatted list of service codes available for AWS services.
394              
395             Length constraints: Minimum of 0 item(s) in the list. Maximum of 100 item(s) in the list.
396              
397             Required: No
398              
399             =item B
400              
401             =back
402              
403             =cut
404              
405             $API_SPEC{'DescribeServices'} = {
406             language => { type => SCALAR, regex => qr/^(en|ja)$/i, optional => 1, default => $DEF_LANG, },
407             serviceCodeList => { type => ARRAYREF, optional => 1 },
408             };
409              
410             sub DescribeServices {
411             ### Enter: (caller(0))[3]
412             my( $rez ) = _genericCallHandler( @_ );
413             ### Exit: (caller(0))[3]
414             return $rez;
415             }
416              
417             # #################################################################################################
418             ## DescribeSeverityLevels
419              
420             =head2 DescribeSeverityLevels( )
421              
422             Returns the list of severity levels that you can assign to an AWS
423             Support case. The severity level for a case is also a field in the
424             CaseDetails data type included in any CreateCase request.
425              
426             Refer to L
427              
428             =over 4
429              
430             =item B
431              
432             =item Language I<(optional string)>
433              
434             The ISO 639-1 code for the language in which AWS provides support. AWS
435             Support currently supports English ("en") and Japanese ("ja"). Language
436             parameters must be passed explicitly for operations that take them.
437              
438             =item B
439              
440             =back
441              
442             =cut
443              
444             $API_SPEC{'DescribeSeverityLevels'} = {
445             language => { type => SCALAR, regex => qr/^(en|ja)$/i, optional => 1, default => $DEF_LANG, },
446             };
447              
448             sub DescribeSeverityLevels {
449             ### Enter: (caller(0))[3]
450             my( $rez ) = _genericCallHandler( @_ );
451             ### Exit: (caller(0))[3]
452             return $rez;
453             }
454              
455             # #################################################################################################
456             ## DescribeTrustedAdvisorCheckRefreshStatuses
457              
458             =head2 DescribeTrustedAdvisorCheckRefreshStatuses( )
459              
460             Returns the refresh status of the Trusted Advisor checks that have the
461             specified check IDs. Check IDs can be obtained by calling DescribeTrustedAdvisorChecks.
462              
463             Refer to L
464              
465             =over 4
466              
467             =item B
468              
469             =item checkIds B<(required array)>
470              
471             The IDs of the Trusted Advisor checks.
472              
473             =item B
474              
475             =back
476              
477             =cut
478              
479             $API_SPEC{'DescribeTrustedAdvisorCheckRefreshStatuses'} = {
480             checkIds => { type => ARRAYREF },
481             };
482              
483             sub DescribeTrustedAdvisorCheckRefreshStatuses {
484             ### Enter: (caller(0))[3]
485             my( $rez ) = _genericCallHandler( @_ );
486             ### Exit: (caller(0))[3]
487             return $rez;
488             }
489              
490             # #################################################################################################
491             ## DescribeTrustedAdvisorCheckResult
492              
493             =head2 DescribeTrustedAdvisorCheckResult( )
494              
495             Returns the results of the Trusted Advisor check that has the specified
496             check ID. Check IDs can be obtained by calling DescribeTrustedAdvisorChecks.
497              
498             The response contains a TrustedAdvisorCheckResult object, which contains these three objects:
499              
500             TrustedAdvisorCategorySpecificSummary
501             TrustedAdvisorResourceDetail
502             TrustedAdvisorResourcesSummary
503              
504             In addition, the response contains these fields:
505              
506             Status. The alert status of the check: "ok" (green), "warning" (yellow), "error" (red), or "not_available".
507             Timestamp. The time of the last refresh of the check.
508             CheckId. The unique identifier for the check.
509              
510             Refer to L
511              
512             =over 4
513              
514             =item B
515              
516             =item checkIds B<(required string)>
517              
518             The ID of the Trusted Advisor check.
519              
520             =item Language I<(optional string)>
521              
522             The ISO 639-1 code for the language in which AWS provides support. AWS
523             Support currently supports English ("en") and Japanese ("ja"). Language
524             parameters must be passed explicitly for operations that take them.
525              
526             =item B
527              
528             =back
529              
530             =cut
531              
532             $API_SPEC{'DescribeTrustedAdvisorCheckResult'} = {
533             checkId => { type => SCALAR },
534             language => { type => SCALAR, regex => qr/^(en|ja)$/i, optional => 1, default => $DEF_LANG, },
535             };
536              
537             sub DescribeTrustedAdvisorCheckResult {
538             ### Enter: (caller(0))[3]
539             my( $rez ) = _genericCallHandler( @_ );
540             ### Exit: (caller(0))[3]
541             return $rez;
542             }
543              
544             # #################################################################################################
545             ## DescribeTrustedAdvisorCheckSummaries
546              
547             =head2 DescribeTrustedAdvisorCheckSummaries( )
548              
549             Returns the summaries of the results of the Trusted Advisor checks that
550             have the specified check IDs. Check IDs can be obtained by calling DescribeTrustedAdvisorChecks.
551              
552             The response contains an array of TrustedAdvisorCheckSummary objects.
553              
554             Refer to L
555              
556             =over 4
557              
558             =item B
559              
560             =item checkIds B<(required array)>
561              
562             The IDs of the Trusted Advisor checks.
563              
564             =item B
565              
566             =back
567              
568             =cut
569              
570             $API_SPEC{'DescribeTrustedAdvisorCheckSummaries'} = {
571             checkId => { type => ARRAYREF },
572             };
573              
574             sub DescribeTrustedAdvisorCheckSummaries {
575             ### Enter: (caller(0))[3]
576             my( $rez ) = _genericCallHandler( @_ );
577             ### Exit: (caller(0))[3]
578             return $rez;
579             }
580              
581             # #################################################################################################
582             ## DescribeTrustedAdvisorChecks
583              
584             =head2 DescribeTrustedAdvisorChecks( )
585              
586             Returns information about all available Trusted Advisor checks,
587             including name, ID, category, description, and metadata. You must
588             specify a language code; English ("en") and Japanese ("ja") are
589             currently supported.
590              
591             The response contains a TrustedAdvisorCheckDescription for each check.
592              
593             Refer to L
594              
595             =over 4
596              
597             =item B
598              
599             =item Language I<(optional string)>
600              
601             The ISO 639-1 code for the language in which AWS provides support. AWS
602             Support currently supports English ("en") and Japanese ("ja"). Language
603             parameters must be passed explicitly for operations that take them.
604              
605             =item B
606              
607             =back
608              
609             =cut
610              
611             $API_SPEC{'DescribeTrustedAdvisorChecks'} = {
612             language => { type => SCALAR, regex => qr/^(en|ja)$/i, optional => 1, default => $DEF_LANG, },
613             };
614              
615             sub DescribeTrustedAdvisorChecks {
616             ### Enter: (caller(0))[3]
617             my( $rez ) = _genericCallHandler( @_ );
618             ### Exit: (caller(0))[3]
619             return $rez;
620             }
621              
622             # #################################################################################################
623             ## RefreshTrustedAdvisorCheck
624              
625             =head2 RefreshTrustedAdvisorCheck( )
626              
627             Requests a refresh of the Trusted Advisor check that has the specified
628             check ID. Check IDs can be obtained by calling DescribeTrustedAdvisorChecks.
629              
630             The response contains a TrustedAdvisorCheckRefreshStatus object, which contains these fields:
631              
632             Status. The refresh status of the check: "none", "enqueued", "processing", "success", or "abandoned".
633             MillisUntilNextRefreshable. The amount of time, in milliseconds, until the check is eligible for refresh.
634             CheckId. The unique identifier for the check.
635              
636             Refer to L
637              
638             =over 4
639              
640             =item B
641              
642             =item checkId B<(required string)>
643              
644             The ID of the Trusted Advisor check.
645              
646             =item B
647              
648             =back
649              
650             =cut
651              
652             $API_SPEC{'RefreshTrustedAdvisorCheck'} = {
653             checkId => { type => SCALAR }
654             };
655              
656             sub RefreshTrustedAdvisorCheck {
657             ### Enter: (caller(0))[3]
658             my( $rez ) = _genericCallHandler( @_ );
659             ### Exit: (caller(0))[3]
660             return $rez;
661             }
662              
663             # #################################################################################################
664             # ResolveCase
665              
666             =head2 ResolveCase( )
667              
668             Takes a CaseId and returns the initial state of the case along with
669             the state of the case after the call to ResolveCase completed.
670              
671             Refer to L
672              
673             =over 4
674              
675             =item B
676              
677             =item caseId B<(required string)>
678              
679             CaseId
680             The AWS Support case ID requested or returned in the call. The case ID
681             is an alphanumeric string formatted as shown in this example:
682             case-12345678910-2013-c4c1d2bf33c5cf47
683              
684             =item B
685              
686             =back
687              
688             =cut
689              
690             $API_SPEC{'ResolveCase'} = {
691             checkId => { type => SCALAR }
692             };
693              
694             sub ResolveCase {
695             ### Enter: (caller(0))[3]
696             my( $rez ) = _genericCallHandler( @_ );
697             ### Exit: (caller(0))[3]
698             return $rez;
699             }
700              
701             # #################################################################################################
702              
703             =head1 AUTHOR
704              
705             Matthew Cox, C<< >>
706              
707             =head1 BUGS
708              
709             Please report any bugs or feature requests to C, or through
710             the web interface at L. I will be notified, and then you'll
711             automatically be notified of progress on your bug as I make changes.
712              
713             =head1 SUPPORT
714              
715             You can find documentation for this module with the perldoc command.
716              
717             perldoc WebService::Amazon::Support
718              
719              
720             You can also look for information at:
721              
722             =over 4
723              
724             =item * RT: CPAN's request tracker (report bugs here)
725              
726             L
727              
728             =item * AnnoCPAN: Annotated CPAN documentation
729              
730             L
731              
732             =item * CPAN Ratings
733              
734             L
735              
736             =item * Search CPAN
737              
738             L
739              
740             =back
741              
742              
743             =head1 ACKNOWLEDGEMENTS
744              
745             =head1 SEE ALSO
746              
747             perl(1), L, L, L, L, L, L, L
748              
749             =head1 LICENSE AND COPYRIGHT
750              
751             Copyright 2015 Matthew Cox.
752              
753             This program is free software; you can redistribute it and/or modify it
754             under the terms of the the Artistic License (2.0). You may obtain a
755             copy of the full license at:
756              
757             L
758              
759             Any use, modification, and distribution of the Standard or Modified
760             Versions is governed by this Artistic License. By using, modifying or
761             distributing the Package, you accept this license. Do not use, modify,
762             or distribute the Package, if you do not accept this license.
763              
764             If your Modified Version has been derived from a Modified Version made
765             by someone other than you, you are nevertheless required to ensure that
766             your Modified Version complies with the requirements of this license.
767              
768             This license does not grant you the right to use any trademark, service
769             mark, tradename, or logo of the Copyright Holder.
770              
771             This license includes the non-exclusive, worldwide, free-of-charge
772             patent license to make, have made, use, offer to sell, sell, import and
773             otherwise transfer the Package with respect to any patent claims
774             licensable by the Copyright Holder that are necessarily infringed by the
775             Package. If you institute patent litigation (including a cross-claim or
776             counterclaim) against any party alleging that the Package constitutes
777             direct or contributory patent infringement, then this Artistic License
778             to you shall terminate on the date that such litigation is filed.
779              
780             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
781             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
782             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
783             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
784             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
785             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
786             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
787             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
788              
789              
790             =cut
791              
792             1; # End of WebService::Amazon::Support
793             __END__