AWS-CLIWrapper

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

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
    [DOCUMENTATION]
        - Added LFMF details! (PR #7)

1.04  2014-08-21

Changes  view on Meta::CPAN

        - awscli >= 0.14.0 requires upper-case parameters "Key",
          "Values", "Value", "Name" in such --filter. But < 1.14.0
          requires lower-case parameters "key", "values", "value",
         "name". So AWS::CLIWrapper converts upper/lower-case by
         version of awscli.
        - awscli >= 0.14.0 requires --count pramter in ec2
          run-instances, but < 0.14.0 requires --min-count and
          --max-count. So AWS::CLIWrapper converts these parameters by
          version of awscli
        - awscli >= 0.15.0 changed "s3" to "s3api" and "s3" became
          another command... So AWS::CLIWrapper calls "s3api"
          internally instead of "s3" if awscli >= 0.15.0 and
          subcommand seems to old "s3"'s one(--list-buckets,
          --put-object and so on), and calls "s3" instead of "s3api"
          if awscli < 0.15.0.
        - I gave up to work around incompatible changes in type of
          returned data structure. For example, awscli 1.0.0
          "elb describe-load-balancers" returns hash, on the other
          hand, awscli 0.9.3 returns list. Please upgrade awscli
          carefully.

0.09  2013-09-02
  * Update document on nofork and timeout (thanks @mschrader)
  * Add some methods for aws-cli/0.16.0

0.08  2013-07-05
  * Potential 'nofork' option to allow calling IPC::Cmd::run vs. run_forked (issue #1, thanks @mschrader)

0.07  2013-06-19
  * Add "output_file" key name of parameter for aws s3 get-object
  * Enable to specify timeout before aborting "aws" command

0.06  2013-06-12
  * Add some methods for aws-cli/0.12.0
  * Fix died when failed to parse result as JSON (aws s3)

0.05  2013-05-01
  * Add some methods for latest awscli (0.9.2)

0.04  2013-04-30
  * Adjust $Error for incompatible changes of aws-cli/botocore

lib/AWS/CLIWrapper.pm  view on Meta::CPAN

#     if ($type && $type eq 'HASH') {
#         for my $hk (keys %$v) {
#             if ($hk =~ /^(?:Key|Name|Values|Values)$/) {
#                 $v->{lc($hk)} = delete $v->{$hk};
#             }
#         }
#     }

#     return $v;
# }
# Drop support < 0.14.0 for preventing execute aws command in loading this module
*_compat_kv = *_compat_kv_uc;

sub json { $_[0]->{json} }

sub _execute {
    my $self    = shift;
    my $service = shift;
    my $operation = shift;
    my @cmd = ($self->awscli_path, @{$self->{opt}}, $service, $operation);
    if ($service eq 'ec2' && $operation eq 'wait') {

lib/AWS/CLIWrapper.pm  view on Meta::CPAN

    }
}

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:/;

lib/AWS/CLIWrapper.pm  view on Meta::CPAN

=item B<workspaces>($operation:Str, $param:HashRef, %opt:Hash)

=item B<workspaces_web>($operation:Str, $param:HashRef, %opt:Hash)

=item B<xray>($operation:Str, $param:HashRef, %opt:Hash)

AWS::CLIWrapper provides methods same as services of aws-cli. Please refer to `aws help`.

First arg "operation" is same as operation of aws-cli. Please refer to `aws SERVICE help`.

Second arg "param" is same as command line option of aws-cli.
Please refer to `aws SERVICE OPERATION help`.

Key of param is string that trimmed leading "--" and replaced "-" to "_" for command line option (--instance-ids -> instance_ids).
Value of param is SCALAR or ARRAYREF or HASHREF.

You can specify C<(boolean)> parameter by C<$AWS::CLIWrapper::true> or C<$AWS::CLIWrapper::false>.

    my $res = $aws->ec2('assign-private-ip-addresses', {
        network_interface_id => $eni_id,
        private_ip_addresses => [ $private_ip_1, $private_ip_2 ],
        allow_reassignment   => $AWS::CLIWrapper::true,
       })

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.

lib/AWS/CLIWrapper.pm  view on Meta::CPAN


=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

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

=item AWS_SECRET_ACCESS_KEY

=item AWS_DEFAULT_REGION

See documents of aws-cli.

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();
};

t/06_catch_errors.t  view on Meta::CPAN

  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 ($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";

t/06_catch_errors.t  view on Meta::CPAN


  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

  }
}

sub version {
  print "aws-cli/2.42.4242\n";
  exit 0;
}

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": [



( run in 0.673 second using v1.01-cache-2.11-cpan-f56aa216473 )