view release on metacpan or search on metacpan
Revision history for AWS::CLIWrapper
1.27 2023-06-29
[IMPROVEMENTS]
- Optionally catch aws-cli errors and retry (PR #23 by @nohuhu)
- Add servics with aws-cli/1.27.163
1.26 2023-05-25
[IMPROVEMENTS]
- Add `region` method to allow introspection on constructor arguments (PR #22 by @nohuhu)
1.25 2023-03-16
[BUG FIXES]
- Fix AWS_CLIWRAPPER_TIMEOUT test (PR #20 by @nohuhu)
1.24 2023-03-15
[IMPROVEMENTS]
- Allow overriding aws-cli execution timeout via environment variable (PR #19 by @nohuhu)
- Add servics with aws-cli/1.27.91
1.23 2022-03-23
[IMPROVEMENTS]
- Fix test suite fails with aws-cli v2 (rt 141885)
1.22 2022-03-17
[IMPROVEMENTS]
- optionally croak() on errors (PR #18 by @nohuhu)
- Add servics with aws-cli/1.22.76
1.21 2021-05-20
[IMPROVEMENTS]
- Add servics with aws-cli/1.19.76
1.20 2021-02-12
[IMPROVEMENTS]
- Add servics with aws-cli/1.19.6
- Specified min perl version both in module and dist metadata
- Added github repo to dist metadata
- Add servics with aws-cli/1.10.9 (PR #11 by @mithun)
1.09 2015-10-02
[IMPROVEMENTS]
- Support ec2 wait (PR #9 by @negachov)
1.08 2015-08-19
[IMPROVEMENTS]
- write stdout/stderr message in debug mode (PR #8 by @limitusus)
1.07 2015-07-21
[IMPROVEMENTS]
- Don't execute aws command in load phase
1.06 2014-11-25
[IMPROVEMENTS]
- s3 OPERATION can take --include or --exclude option multiple times
1.05 2014-09-29
cpanfile
lib/AWS/CLIWrapper.pm
Makefile.PL
MANIFEST This list of files
t/00_compile.t
t/01_new.t
t/03_awscli_path.t
t/03_awscli_timeout.t
t/03_awscli_version.t
t/03_region.t
t/04_errors.t
t/05_catch_error_options.t
t/06_catch_errors.t
t/bin/mock-aws
xt/01_podspell.t
xt/02_perlcritic.t
xt/03_pod.t
xt/05_dependencies.t
xt/10_ec2.t
xt/11_struct-in-list.t
xt/12_nested-boolean.t
xt/19_error.t
xt/20_s3-sync.t
xt/30_compat.t
xt/90_dependencies.t
xt/91_usedmodules.t
xt/92_usedfunctions.t
xt/perlcriticrc
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
lib/AWS/CLIWrapper.pm view on Meta::CPAN
push @opt, param2opt($k, $v);
}
}
my $self = bless {
region => $region,
opt => \@opt,
json => JSON->new,
param => \%param,
awscli_path => $param{awscli_path} || 'aws',
croak_on_error => !!$param{croak_on_error},
timeout => (defined $ENV{AWS_CLIWRAPPER_TIMEOUT}) ? $ENV{AWS_CLIWRAPPER_TIMEOUT} : 30,
}, $class;
return $self;
}
sub region { shift->{region} }
sub awscli_path {
my ($self) = @_;
lib/AWS/CLIWrapper.pm view on Meta::CPAN
$v = $1;
} else {
$v = 0;
}
version->parse($v);
};
}
return $AWSCLI_VERSION;
}
sub catch_error_pattern {
my ($self) = @_;
return $ENV{AWS_CLIWRAPPER_CATCH_ERROR_PATTERN}
if defined $ENV{AWS_CLIWRAPPER_CATCH_ERROR_PATTERN};
return $self->{param}->{catch_error_pattern}
if defined $self->{param}->{catch_error_pattern};
return;
}
sub catch_error_retries {
my ($self) = @_;
my $retries = defined $ENV{AWS_CLIWRAPPER_CATCH_ERROR_RETRIES}
? $ENV{AWS_CLIWRAPPER_CATCH_ERROR_RETRIES}
: defined $self->{param}->{catch_error_retries}
? $self->{param}->{catch_error_retries}
: $DEFAULT_CATCH_ERROR_RETRIES;
$retries = $DEFAULT_CATCH_ERROR_RETRIES if $retries < 0;
return $retries;
}
sub catch_error_min_delay {
my ($self) = @_;
my $min_delay = defined $ENV{AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY}
? $ENV{AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY}
: defined $self->{param}->{catch_error_min_delay}
? $self->{param}->{catch_error_min_delay}
: $DEFAULT_CATCH_ERROR_MIN_DELAY;
$min_delay = $DEFAULT_CATCH_ERROR_MIN_DELAY if $min_delay < 0;
return $min_delay;
}
sub catch_error_max_delay {
my ($self) = @_;
my $min_delay = $self->catch_error_min_delay;
my $max_delay = defined $ENV{AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY}
? $ENV{AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY}
: defined $self->{param}->{catch_error_max_delay}
? $self->{param}->{catch_error_max_delay}
: $DEFAULT_CATCH_ERROR_MAX_DELAY;
$max_delay = $DEFAULT_CATCH_ERROR_MAX_DELAY if $max_delay < 0;
$max_delay = $min_delay if $min_delay > $max_delay;
return $max_delay;
}
sub catch_error_delay {
my ($self) = @_;
my $min = $self->catch_error_min_delay;
my $max = $self->catch_error_max_delay;
return $min == $max ? $min : $min + (int rand $max - $min);
}
sub param2opt {
my($k, $v) = @_;
my @v;
$k =~ s/_/-/g;
lib/AWS/CLIWrapper.pm view on Meta::CPAN
my @o = param2opt($k, $v);
if ($service eq 's3' && $k =~ /^(?:include|exclude)$/) {
my $optk = shift @o;
@o = map { $optk => $_ } @o;
}
push @cmd, @o;
}
@cmd = map { shell_quote($_) } @cmd;
warn "cmd: ".join(' ', @cmd) if $ENV{AWSCLI_DEBUG};
my $error_re = $self->catch_error_pattern;
my $retries = $error_re ? $self->catch_error_retries : 0;
RETRY: {
$Error = { Message => '', Code => '' };
my $exit_value = $self->_run(\%opt, \@cmd);
my $ret = $self->_handle($service, $operation, $exit_value);
return $ret unless $Error->{Code};
if ($retries-- > 0 and $Error->{Message} =~ $error_re) {
my $delay = $self->catch_error_delay;
warn "Caught error matching $error_re, sleeping $delay seconds before retrying\n"
if $ENV{AWSCLI_DEBUG};
sleep $delay;
redo RETRY;
}
croak $Error->{Message} if $self->{croak_on_error};
return $ret;
}
}
sub _run {
my ($self, $opt, $cmd) = @_;
my $ret;
if (exists $opt->{'nofork'} && $opt->{'nofork'}) {
# better for perl debugger
my($ok, $err, $buf, $stdout_buf, $stderr_buf) = IPC::Cmd::run(
command => join(' ', @$cmd),
timeout => $opt->{timeout} || $self->{timeout},
);
$ret->{stdout} = join "", @$stdout_buf;
$ret->{err_msg} = (defined $err ? "$err\n" : "") . join "", @$stderr_buf;
if ($ok) {
$ret->{exit_code} = 0;
$ret->{timeout} = 0;
} else {
$ret->{exit_code} = 2;
$ret->{timeout} = 1 if defined $err && $err =~ /^IPC::Cmd::TimeOut:/;
}
print "";
} else {
$ret = IPC::Cmd::run_forked(join(' ', @$cmd), {
timeout => $opt->{timeout} || $self->{timeout},
});
}
return $ret;
}
lib/AWS/CLIWrapper.pm view on Meta::CPAN
# exception from decode() from catching by outer
# __DIE__ handler.
local $SIG{__DIE__} = sub {};
$self->json->decode($json);
};
if ($@) {
if ($ENV{AWSCLI_DEBUG}) {
warn $@;
warn qq|stdout: "$ret->{stdout}"|;
warn qq|err_msg: "$ret->{err_msg}"|;
}
return $json || 'success';
}
return $ret;
} else {
my $stdout_str = $ret->{stdout};
if ($stdout_str && $stdout_str =~ /^{/) {
my $json = $stdout_str;
warn sprintf("%s.%s[%s]: %s\n",
$service, $operation, 'NG', $json,
lib/AWS/CLIWrapper.pm view on Meta::CPAN
my($ret) = $self->json->decode_prefix($json);
if (exists $ret->{Errors} && ref($ret->{Errors}) eq 'ARRAY') {
$Error = $ret->{Errors}[0];
} elsif (exists $ret->{Response}{Errors}{Error}) {
# old structure (maybe botocore < 0.7.0)
$Error = $ret->{Response}{Errors}{Error};
} else {
$Error = { Message => 'Unknown', Code => 'Unknown' };
}
} else {
my $msg = $ret->{err_msg};
warn sprintf("%s.%s[%s]: %s\n",
$service, $operation, 'NG', $msg,
) if $ENV{AWSCLI_DEBUG};
$Error = { Message => $msg, Code => 'Unknown' };
}
return;
}
}
lib/AWS/CLIWrapper.pm view on Meta::CPAN
Constructor of AWS::CLIWrapper. Acceptable AWS CLI params are:
region region_name:Str
profile profile_name:Str
endpoint_url endpoint_url:Str
Additionally, the these params can be used to control the wrapper behavior:
nofork Truthy to avoid forking when executing `aws`
timeout `aws` execution timeout
croak_on_error Truthy to croak() with the error message when `aws`
exits with non-zero code
catch_error_pattern Regexp pattern to match for error handling.
catch_error_retries Retries for handling errors.
catch_error_min_delay Minimal delay before retrying `aws` call
when an error was caught.
catch_error_max_delay Maximal delay before retrying `aws` call.
See below for more detailed explanation.
=item B<accessanalyzer>($operation:Str, $param:HashRef, %opt:Hash)
=item B<account>($operation:Str, $param:HashRef, %opt:Hash)
=item B<acm>($operation:Str, $param:HashRef, %opt:Hash)
=item B<acm_pca>($operation:Str, $param:HashRef, %opt:Hash)
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
AWS_CLIWRAPPER_CATCH_ERROR_PATTERN takes precedence over this option, if both
are defined.
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)
lib/AWS/CLIWrapper.pm view on Meta::CPAN
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
How many times to retry command execution if an error was caught. Default is 3.
=item AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY
Minimal delay before retrying command execution if an error was caught, in seconds.
Default is 3.
=item AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY
Maximal delay before retrying command execution, in seconds. Default is 10.
=item AWS_CONFIG_FILE
=item AWS_ACCESS_KEY_ID
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
t/04_errors.t view on Meta::CPAN
use strict;
use Test::More;
use AWS::CLIWrapper;
# 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
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',
},
'env-catch_error_retries' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_RETRIES => 10,
},
method => 'catch_error_retries',
want => 10,
},
'env-catch_error_retries-invalid' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_RETRIES => -10,
},
method => 'catch_error_retries',
want => 3,
},
'env-catch_error_min_delay' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => 15,
},
method => 'catch_error_min_delay',
want => 15,
},
'env-catch_error_min_delay-invalid' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => -15,
},
method => 'catch_error_min_delay',
want => 3,
},
'env-catch_error_max_delay' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => 30,
},
method => 'catch_error_max_delay',
want => 30,
},
'env-catch_error_max_delay-invalid' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => -30,
},
method => 'catch_error_max_delay',
want => 10,
},
'env-catch_error_max_delay-gt-min_delay' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => 30,
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => 15,
},
method => 'catch_error_max_delay',
want => 30,
},
'args-catch_error_pattern' => {
args => {
catch_error_pattern => 'bar',
},
method => 'catch_error_pattern',
want => 'bar',
},
'env-over-args-catch_error_pattern' => {
args => {
catch_error_pattern => 'qux',
},
env => {
AWS_CLIWRAPPER_CATCH_ERROR_PATTERN => 'baz',
},
method => 'catch_error_pattern',
want => 'baz',
},
'args-catch_error_retries' => {
args => {
catch_error_retries => 10,
},
method => 'catch_error_retries',
want => 10,
},
'env-over-args-catch_error_retries' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_RETRIES => 20,
},
args => {
catch_error_retries => 10,
},
method => 'catch_error_retries',
want => 20,
},
'args-catch_error_min_delay' => {
args => {
catch_error_min_delay => 20,
},
method => 'catch_error_min_delay',
want => 20,
},
'env-over-args-catch_error_min_delay' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => 40,
},
args => {
catch_error_min_delay => 20,
},
method => 'catch_error_min_delay',
want => 40,
},
'args-catch_error_max_delay' => {
args => {
catch_error_max_delay => 60,
},
method => 'catch_error_max_delay',
want => 60,
},
'env-over-args-catch_error_max_delay' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => 120,
},
args => {
catch_error_max_delay => 60,
},
method => 'catch_error_max_delay',
want => 120,
},
'min-max-catch_error_delay' => {
args => {
catch_error_min_delay => 30,
catch_error_max_delay => 30,
},
method => 'catch_error_delay',
want => 30,
},
'zero-catch_error_delay' => {
args => {
catch_error_min_delay => 0,
catch_error_max_delay => 0,
},
method => 'catch_error_delay',
want => 0,
},
}
t/06_catch_errors.t view on Meta::CPAN
my ($wrapper_args, $env, $command, $subcommand, $cmd_args)
= @$test{qw(wrapper_args env command subcommand cmd_args)};
$env = {} unless $env;
my ($tmp_fh, $tmp_name) = tempfile;
print $tmp_fh $test->{retries} || 1;
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";
}
like "$@", $test->{exception}, "$test_name exception";
like $AWS::CLIWrapper::Error->{Message}, $test->{error_msg_re},
"$test_name error message";
is_deeply $res, $test->{want}, "$test_name result";
}
done_testing;
__DATA__
# line 60
{
'no-error' => {
command => 'ecs',
subcommand => 'list-clusters',
error_to_die_with => undef,
error_msg_re => qr{^$},
exception => qr{^$},
want => {
clusterArns => [
"arn:aws:ecs:us-foo-1:123456789:cluster/foo",
"arn:aws:ecs:us-foo-1:123456789:cluster/bar",
"arn:aws:ecs:us-foo-1:123456789:cluster/baz"
],
}
},
'no-croak' => {
command => 'ecs',
subcommand => 'list-clusters',
error_to_die_with => 'uh-oh',
error_msg_re => qr{uh-oh},
exception => qr{^$},
want => undef,
},
'with-croak' => {
wrapper_args => { croak_on_error => 1 },
command => 'ecs',
subcommand => 'list-clusters',
error_to_die_with => 'foobaroo!',
error_msg_re => qr{foobaroo},
exception => qr{foobaroo},
want => undef,
},
'catch-no-croak' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_PATTERN => 'FUBAR',
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => 0,
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => 0,
},
command => 'ecs',
subcommand => 'list-clusters',
error_to_die_with => 'FUBAR',
retries => 2,
error_msg_re => qr{^$},
exception => qr{^$},
want => {
clusterArns => [
"arn:aws:ecs:us-foo-1:123456789:cluster/foo",
"arn:aws:ecs:us-foo-1:123456789:cluster/bar",
"arn:aws:ecs:us-foo-1:123456789:cluster/baz"
],
}
},
'catch-with-croak' => {
env => {
AWS_CLIWRAPPER_CATCH_ERROR_PATTERN => 'throbbe',
AWS_CLIWRAPPER_CATCH_ERROR_MIN_DELAY => 0,
AWS_CLIWRAPPER_CATCH_ERROR_MAX_DELAY => 0,
},
command => 'ecs',
subcommand => 'list-clusters',
error_to_die_with => 'zong throbbe fung',
retries => 3,
error_msg_re => qr{^$},
exception => qr{^$},
want => {
clusterArns => [
"arn:aws:ecs:us-foo-1:123456789:cluster/foo",
"arn:aws:ecs:us-foo-1:123456789:cluster/bar",
"arn:aws:ecs:us-foo-1:123456789:cluster/baz"
],
}
},
}
t/bin/mock-aws view on Meta::CPAN
eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}'
if 0;
use strict;
use warnings;
no warnings 'uninitialized';
version() if $ARGV[0] eq "--version";
handle_die_with_error() if $ENV{AWS_CLIWRAPPER_TEST_DIE_WITH_ERROR};
my $cmd = shift @ARGV;
my $subcmd = shift @ARGV;
handle($cmd, $subcmd);
sub handle {
my ($cmd, $subcmd) = @_;
$subcmd =~ s/-/_/g;
t/bin/mock-aws view on Meta::CPAN
if ('CODE' eq ref $handler) {
$handler->();
exit 0;
}
else {
help();
}
}
sub handle_die_with_error {
my $counter_file = $ENV{AWS_CLIWRAPPER_TEST_ERROR_COUNTER_FILE};
return unless -f $counter_file;
open my $fh, "<", $counter_file or die "Cannot open $counter_file for read: $!";
my $counter = <$fh>;
close $fh;
# This logic is the opposite of usual retries: we throw an error for the counter
# number of times and then proceed normally after.
if ($counter-- > 0) {
open $fh, ">", $counter_file or die "Cannot open $counter_file for write: $!";
print $fh $counter;
close $fh;
die $ENV{AWS_CLIWRAPPER_TEST_DIE_WITH_ERROR};
}
}
t/bin/mock-aws view on Meta::CPAN
sub help {
die <<__END__;
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:
aws help
aws <command> help
aws <command> <subcommand> help
aws: error: the following arguments are required: operation
__END__
}
sub ecs_list_clusters {
print <<__END__;
{
"clusterArns": [
"arn:aws:ecs:us-foo-1:123456789:cluster/foo",
"arn:aws:ecs:us-foo-1:123456789:cluster/bar",
xt/12_nested-boolean.t view on Meta::CPAN
# -*- mode: cperl -*-
use strict;
use Test::More;
use AWS::CLIWrapper;
my $AMI_ID = 'ami-0cc905e12087478be'; # Ubuntu 18.04
my $aws = AWS::CLIWrapper->new;
my $res;
my $err;
$res = $aws->ec2('run-instances', {
count => 1,
image_id => $AMI_ID,
instance_type => 't2.micro',
key_name => 'hirose31-aws-tokyo',
network_interfaces => [
{
DeviceIndex => 0,
SubnetId => 'subnet-00c69dad8729ad024',
xt/19_error.t view on Meta::CPAN
# -*- mode: cperl -*-
use strict;
use Test::More;
use AWS::CLIWrapper;
my $aws = AWS::CLIWrapper->new;
my $res;
my $err;
### unknown operation
$res = $aws->ec2('unknown-operation');
$err = $AWS::CLIWrapper::Error;
ok(!$res, 'unknown operation');
is($err->{Code}, 'Unknown', 'err Code');
like($err->{Message}, qr/operation: Invalid choice/i, 'err Message');
### invalid option
$res = $aws->ec2('describe-instances', { invalid_option => 'blah' });
$err = $AWS::CLIWrapper::Error;
ok(!$res, 'invalid option');
is($err->{Code}, 'Unknown', 'err Code');
like($err->{Message}, qr/(Unknown options:|Something is wrong)/, 'err Message');
### invalid option value
$res = $aws->ec2('describe-instances', { instance_ids => ['blah'] });
$err = $AWS::CLIWrapper::Error;
ok(!$res, 'invalid option value');
like($err->{Code}, qr/(Unknown|InvalidInstanceID.Malformed)/, 'err Code');
like($err->{Message}, qr/(Invalid id:|Unknown)/, 'err Message');
### required option
$res = $aws->ec2('run-instances');
$err = $AWS::CLIWrapper::Error;
ok(!$res, 'required option');
is($err->{Code}, 'Unknown', 'err Code');
like($err->{Message}, qr/(?:is required|MissingParameter)/, 'err Message');
###
done_testing;