AWS-CLIWrapper
view release on metacpan or search on metacpan
lib/AWS/CLIWrapper.pm view on Meta::CPAN
use AWS::CLIWrapper;
my $aws = AWS::CLIWrapper->new(
region => 'us-west-1',
);
my $res = $aws->ec2(
'describe-instances' => {
instance_ids => ['i-XXXXX', 'i-YYYYY'],
},
timeout => 18, # optional. default is 30 seconds
);
if ($res) {
for my $rs ( @{ $res->{Reservations} }) {
for my $is (@{ $rs->{Instances} }) {
print $is->{InstanceId},"\n";
}
}
} else {
warn $AWS::CLIWrapper::Error->{Code};
lib/AWS/CLIWrapper.pm view on Meta::CPAN
Special case: s3 OPERATION can take --include and --exclude option multiple times. For example "aws s3 sync --exclude 'foo' --exclude 'bar' LocalPath s3://S3Path", Pass ARRAYREF as value of C<include> or C<exclude> in this case:
my $res = $aws->s3('sync', ['LocalPath', 's3://S3Path'], {
exclude => ['foo', 'bar'],
})
Third arg "opt" is optional. Available key/values are below:
timeout => Int
Maximum time the "aws" command is allowed to run before aborting.
default is 30 seconds, unless overridden with AWS_CLIWRAPPER_TIMEOUT environment variable.
nofork => Int (>0)
Call IPC::Cmd::run vs. IPC::Cmd::run_forked (mostly useful if/when in perl debugger). Note: 'timeout', if used with 'nofork', will merely cause an alarm and return. ie. 'run' will NOT kill the awscli command like 'run_forked' will.
croak_on_error => Int (>0)
When set to a truthy value, this will make AWS::CLIWrapper to croak() with error message when `aws` command exits with non-zero status. Default behavior is to set $AWS::CLIWrapper::Error and return.
catch_error_pattern => RegExp
When defined, this option will enable catching `aws-cli` errors matching this pattern
and retrying `aws-cli` command execution. Environment variable
lib/AWS/CLIWrapper.pm view on Meta::CPAN
Default is undef.
catch_error_retries => Int (>= 0)
When defined, this option will set the number of retries to make when `aws-cli` error
was caught with catch_error_pattern, before giving up. Environment variable
AWS_CLIWRAPPER_CATCH_ERROR_RETRIES takes precedence over this option, if both
are defined.
0 (zero) retries is a valid way to turn off error catching via environment variable
in certain scenarios. Negative values are invalid and will be reset to default.
Default is 3.
catch_error_min_delay => Int (>= 0)
When defined, this option will set the minimum delay in seconds before attempting
a retry of failed `aws-cli` execution when the error was caught. Environment variable
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY takes precedence over this option, if both
are defined.
0 (zero) is a valid value. Negative values are invalid and will be reset to default.
Default is 3.
catch_error_max_delay => Int (>= 0)
When defined, this option will set the maximum delay in seconds before attempting
a retry of failed `aws-cli` execution. Environment variable AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY
takes precedence over this option, if both are defined.
0 (zero) is a valid value. Negative values are invalid and will be reset to default.
If catch_error_min_delay is greater than catch_error_max_delay, both are set
to catch_error_min_delay value.
Default is 10.
=back
=head1 ENVIRONMENT
=over 4
=item HOME: used by default by /usr/bin/aws utility to find it's credentials (if none are specified)
Special note: cron on Linux will often have a different HOME "/" instead of "/root" - set $ENV{'HOME'}
to use the default credentials or specify $ENV{'AWS_CONFIG_FILE'} directly.
=item AWS_CLIWRAPPER_TIMEOUT
If this variable is set, this value will be used instead of default timeout (30 seconds) for every
invocation of `aws-cli` that does not have a timeout value provided in the options argument of the
called function.
=item AWS_CLIWRAPPER_CATCH_ERROR_PATTERN
If this variable is set, AWS::CLIWrapper will retry `aws-cli` execution if stdout output
of failed `aws-cli` command matches the pattern. See L<ERROR HANDLING>.
=item AWS_CLIWRAPPER_CATCH_ERROR_RETRIES
lib/AWS/CLIWrapper.pm view on Meta::CPAN
=item AWS_DEFAULT_REGION
See documents of aws-cli.
=back
=head1 ERROR HANDLING
=over 4
By default, when `aws-cli` exits with an error code (> 0), AWS::CLIWrapper will set
the error code and message to $AWS::CLIWrapper::Error (and optionally croak), thus
relaying the error to calling code. While this approach is beneficial 99% of the time,
in some use cases `aws-cli` execution fails for a temporary reason unrelated to
both calling code and AWS::CLIWrapper, and can be safely retried after a short delay.
One of this use cases is executing `aws-cli` on AWS EC2 instances, where `aws-cli`
retrieves its configuration and credentials from the API exposed to the EC2 instance;
at certain times these credentials may be rotated and calling `aws-cli` at exactly
the right moment will cause it to fail with `Unable to locate credentials` error.
To prevent this kind of errors from failing the calling code, AWS::CLIWrapper allows
configuring an RegExp pattern and retry `aws-cli` execution if it fails with an error
matching the configured pattern.
The error catching pattern, as well as other configuration, can be defined either
as AWS::CLIWrapper options in the code, or as respective environment variables
(see L<ENVIRONMENT>).
The actual delay before retrying a failed `aws-cli` execution is computed as a
random value of seconds between catch_error_min_delay (default 3) and catch_error_max_delay
(default 10). Backoff is not supported at this moment.
=back
=head1 AUTHOR
HIROSE Masaaki E<lt>hirose31 _at_ gmail.comE<gt>
=head1 REPOSITORY
L<https://github.com/hirose31/AWS-CLIWrapper>
t/03_awscli_path.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use AWS::CLIWrapper;
subtest 'default' => sub {
my $cli = AWS::CLIWrapper->new;
is $cli->awscli_path, 'aws';
};
subtest 'specify explicit awscli path' => sub {
my $cli = AWS::CLIWrapper->new(awscli_path => '/usr/local/bin/aws');
is $cli->awscli_path, '/usr/local/bin/aws';
};
done_testing;
t/03_awscli_timeout.t view on Meta::CPAN
use strict;
use Test::More;
use AWS::CLIWrapper;
{
local $ENV{AWS_CLIWRAPPER_TIMEOUT} = undef;
my $aws = AWS::CLIWrapper->new();
is $aws->{timeout}, 30, "default timeout is 30 seconds";
}
{
local $ENV{AWS_CLIWRAPPER_TIMEOUT} = 3600;
my $aws = AWS::CLIWrapper->new();
is $aws->{timeout}, 3600, "timeout set via env variable";
}
t/04_errors.t view on Meta::CPAN
# Default error handling
my $aws = AWS::CLIWrapper->new;
if ($aws->awscli_version == 0) {
plan skip_all => 'not found aws command';
} else {
plan tests => 4;
}
my $res = $aws->elbv2();
is $res, undef, "default result is undefined";
# Is this a TODO?
is $AWS::CLIWrapper::Error->{Code}, "Unknown", "default error code match";
my $want_err_msg = qr!exited with code \[\d+\]
stderr:
.*
usage: aws \[options\] <command> <subcommand> \[<subcommand> ...\] \[parameters\]
To see help text, you can run:
aws help
aws <command> help
aws <command> <subcommand> help
!ms;
like $AWS::CLIWrapper::Error->{Message}, $want_err_msg, "default error message match";
# Croaking
my $aws_croak = AWS::CLIWrapper->new(croak_on_error => 1);
eval {
$aws_croak->elbv2();
};
like $@, $want_err_msg, "croak on error message match";
t/05_catch_error_options.t view on Meta::CPAN
use 5.008001;
use strict;
use warnings;
no warnings 'uninitialized';
use Test::More;
use AWS::CLIWrapper;
my %default_args = (
awscli_path => 't/bin/mock-aws',
nofork => 1,
);
my $tests = eval join "\n", <DATA> or die "$@";
for my $test_name (keys %$tests) {
next if @ARGV and not grep { $_ eq $test_name } @ARGV;
my $test = $tests->{$test_name};
my ($args, $env, $method, $want) = @$test{qw(args env method want)};
$env = {} unless $env;
local @ENV{keys %$env} = values %$env;
my $aws = AWS::CLIWrapper->new(%default_args, %{$args || {}});
my $have = $aws->$method;
if ('ARRAY' eq ref $want) {
cmp_ok $have, $_->[0], $_->[1], "$test_name " . (join ' ', @$_) for @$want;
}
else {
is $have, $want, $test_name;
}
}
done_testing;
__DATA__
# line 41
{
'mock-aws version' => {
method => 'awscli_version',
want => '2.42.4242',
},
'default-catch_error_pattern' => {
method => 'catch_error_pattern',
want => undef,
},
'default-catch_error_retries' => {
method => 'catch_error_retries',
want => 3,
},
'default-catch_error_min_delay' => {
method => 'catch_error_min_delay',
want => 3,
},
'default-catch_error_max_delay' => {
method => 'catch_error_max_delay',
want => 10,
},
'default-catch_error_delay' => {
method => 'catch_error_delay',
want => [['>=', 3], ['<=', 10]],
},
'env-catch_error_pattern' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_PATTERN => 'foo',
},
method => 'catch_error_pattern',
want => 'foo',
},
t/06_catch_errors.t view on Meta::CPAN
use 5.008001;
use strict;
use warnings;
no warnings 'uninitialized';
use Test::More;
use File::Temp 'tempfile';
use AWS::CLIWrapper;
my %default_wrapper_args = (
awscli_path => 't/bin/mock-aws',
nofork => 1,
);
my $tests = eval join "\n", <DATA> or die "$@";
for my $test_name (keys %$tests) {
next if @ARGV and not grep { $_ eq $test_name } @ARGV;
my $test = $tests->{$test_name};
t/06_catch_errors.t view on Meta::CPAN
close $tmp_fh;
local $ENV{AWS_CLIWRAPPER_TEST_ERROR_COUNTER_FILE} = $tmp_name;
local $ENV{AWS_CLIWRAPPER_TEST_DIE_WITH_ERROR} = $test->{error_to_die_with}
if $test->{error_to_die_with};
local @ENV{keys %$env} = values %$env;
$AWS::CLIWrapper::Error = { Message => '', Code => '' };
my $aws = AWS::CLIWrapper->new(%default_wrapper_args, %{$wrapper_args || {}});
my $res = eval { $aws->$command($subcommand, @{$cmd_args || []}) };
if ($test->{retries} > 0) {
open my $fh, "<", $tmp_name;
my $counter = <$fh>;
close $fh;
is $counter, 0, "$test_name retry counter exhausted";
}
( run in 0.610 second using v1.01-cache-2.11-cpan-0a6323c29d9 )