AWS-CLIWrapper

 view release on metacpan or  search on metacpan

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

    }

    while (my($k, $v) = each %$param) {
        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;
}

sub _handle {
    my ($self, $service, $operation, $ret) = @_;

    if ($ret->{exit_code} == 0 && $ret->{timeout} == 0) {
        my $json = $ret->{stdout};
        warn sprintf("%s.%s[%s]: %s\n",
                     $service, $operation, 'OK', $json,
                    ) if $ENV{AWSCLI_DEBUG};
        local $@;
        my($ret) = eval {
            # aws s3 returns null HTTP body, so failed to parse as JSON

            # Temporary disable __DIE__ handler to prevent the
            # 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,
                        ) if $ENV{AWSCLI_DEBUG};
            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;
    }
}

# aws help | col -b | perl -ne 'if (/^AVAILABLE/.../^[A-Z]/) {  s/^\s+o\s+// or next; chomp; next if $_ eq 'help'; my $sn = $_; $sn =~ s/-/_/g; printf "sub %-18s { shift->_execute('"'"'%s'"'"', \@_) }\n", $sn, $_ }'
# aws help | col -b | perl -ne 'if (/^AVAILABLE/.../^[A-Z]/) {  s/^\s+o\s+// or next; chomp; next if $_ eq 'help'; my $sn = $_; $sn =~ s/-/_/g; printf "=item B<%s>(\$operation:Str, \$param:HashRef, %%opt:Hash)\n\n", $sn}'
# =item B<s3>($operation:Str, $path:ArrayRef, $param:HashRef, %opt:Hash)
sub accessanalyzer     { shift->_execute('accessanalyzer', @_) }
sub account            { shift->_execute('account', @_) }
sub acm                { shift->_execute('acm', @_) }
sub acm_pca            { shift->_execute('acm-pca', @_) }
sub alexaforbusiness   { shift->_execute('alexaforbusiness', @_) }
sub amp                { shift->_execute('amp', @_) }
sub amplify            { shift->_execute('amplify', @_) }
sub amplifybackend     { shift->_execute('amplifybackend', @_) }
sub amplifyuibuilder   { shift->_execute('amplifyuibuilder', @_) }
sub apigateway         { shift->_execute('apigateway', @_) }
sub apigatewaymanagementapi { shift->_execute('apigatewaymanagementapi', @_) }
sub apigatewayv2       { shift->_execute('apigatewayv2', @_) }
sub appconfig          { shift->_execute('appconfig', @_) }
sub appconfigdata      { shift->_execute('appconfigdata', @_) }
sub appfabric          { shift->_execute('appfabric', @_) }
sub appflow            { shift->_execute('appflow', @_) }
sub appintegrations    { shift->_execute('appintegrations', @_) }
sub application_autoscaling { shift->_execute('application-autoscaling', @_) }
sub application_insights { shift->_execute('application-insights', @_) }
sub applicationcostprofiler { shift->_execute('applicationcostprofiler', @_) }
sub appmesh            { shift->_execute('appmesh', @_) }
sub apprunner          { shift->_execute('apprunner', @_) }
sub appstream          { shift->_execute('appstream', @_) }
sub appsync            { shift->_execute('appsync', @_) }
sub arc_zonal_shift    { shift->_execute('arc-zonal-shift', @_) }
sub athena             { shift->_execute('athena', @_) }
sub auditmanager       { shift->_execute('auditmanager', @_) }
sub autoscaling        { shift->_execute('autoscaling', @_) }
sub autoscaling_plans  { shift->_execute('autoscaling-plans', @_) }
sub backup             { shift->_execute('backup', @_) }
sub backup_gateway     { shift->_execute('backup-gateway', @_) }
sub backupstorage      { shift->_execute('backupstorage', @_) }
sub batch              { shift->_execute('batch', @_) }
sub billingconductor   { shift->_execute('billingconductor', @_) }
sub braket             { shift->_execute('braket', @_) }
sub budgets            { shift->_execute('budgets', @_) }
sub ce                 { shift->_execute('ce', @_) }
sub chime              { shift->_execute('chime', @_) }
sub chime_sdk_identity { shift->_execute('chime-sdk-identity', @_) }
sub chime_sdk_media_pipelines { shift->_execute('chime-sdk-media-pipelines', @_) }
sub chime_sdk_meetings { shift->_execute('chime-sdk-meetings', @_) }
sub chime_sdk_messaging { shift->_execute('chime-sdk-messaging', @_) }
sub chime_sdk_voice    { shift->_execute('chime-sdk-voice', @_) }
sub cleanrooms         { shift->_execute('cleanrooms', @_) }
sub cloud9             { shift->_execute('cloud9', @_) }
sub cloudcontrol       { shift->_execute('cloudcontrol', @_) }
sub clouddirectory     { shift->_execute('clouddirectory', @_) }
sub cloudformation     { shift->_execute('cloudformation', @_) }
sub cloudfront         { shift->_execute('cloudfront', @_) }
sub cloudhsm           { shift->_execute('cloudhsm', @_) }
sub cloudhsmv2         { shift->_execute('cloudhsmv2', @_) }
sub cloudsearch        { shift->_execute('cloudsearch', @_) }
sub cloudsearchdomain  { shift->_execute('cloudsearchdomain', @_) }
sub cloudtrail         { shift->_execute('cloudtrail', @_) }
sub cloudtrail_data    { shift->_execute('cloudtrail-data', @_) }
sub cloudwatch         { shift->_execute('cloudwatch', @_) }
sub codeartifact       { shift->_execute('codeartifact', @_) }
sub codebuild          { shift->_execute('codebuild', @_) }
sub codecatalyst       { shift->_execute('codecatalyst', @_) }

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

sub sso_admin          { shift->_execute('sso-admin', @_) }
sub sso_oidc           { shift->_execute('sso-oidc', @_) }
sub stepfunctions      { shift->_execute('stepfunctions', @_) }
sub storagegateway     { shift->_execute('storagegateway', @_) }
sub sts                { shift->_execute('sts', @_) }
sub support            { shift->_execute('support', @_) }
sub support_app        { shift->_execute('support-app', @_) }
sub swf                { shift->_execute('swf', @_) }
sub synthetics         { shift->_execute('synthetics', @_) }
sub textract           { shift->_execute('textract', @_) }
sub timestream_query   { shift->_execute('timestream-query', @_) }
sub timestream_write   { shift->_execute('timestream-write', @_) }
sub tnb                { shift->_execute('tnb', @_) }
sub transcribe         { shift->_execute('transcribe', @_) }
sub transfer           { shift->_execute('transfer', @_) }
sub translate          { shift->_execute('translate', @_) }
sub verifiedpermissions { shift->_execute('verifiedpermissions', @_) }
sub voice_id           { shift->_execute('voice-id', @_) }
sub vpc_lattice        { shift->_execute('vpc-lattice', @_) }
sub waf                { shift->_execute('waf', @_) }
sub waf_regional       { shift->_execute('waf-regional', @_) }
sub wafv2              { shift->_execute('wafv2', @_) }
sub wellarchitected    { shift->_execute('wellarchitected', @_) }
sub wisdom             { shift->_execute('wisdom', @_) }
sub workdocs           { shift->_execute('workdocs', @_) }
sub worklink           { shift->_execute('worklink', @_) }
sub workmail           { shift->_execute('workmail', @_) }
sub workmailmessageflow { shift->_execute('workmailmessageflow', @_) }
sub workspaces         { shift->_execute('workspaces', @_) }
sub workspaces_web     { shift->_execute('workspaces-web', @_) }
sub xray               { shift->_execute('xray', @_) }

1;

__END__

=encoding utf-8

=head1 NAME

AWS::CLIWrapper - Wrapper module for aws-cli

=head1 SYNOPSIS

    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};
        warn $AWS::CLIWrapper::Error->{Message};
    }

=head1 DESCRIPTION

AWS::CLIWrapper is wrapper module for aws-cli (recommend: awscli >= 1.0.0, requires: >= 0.40.0).

AWS::CLIWrapper is a just wrapper module, so you can do everything what you can do with aws-cli.

See note below about making sure AWS credentials are accessible (especially under crond)

=head1 METHODS

=over 4

=item B<new>($param:HashRef)

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)

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

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

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

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

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

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



( run in 0.737 second using v1.01-cache-2.11-cpan-2398b32b56e )