AWS-CLIWrapper icon indicating copy to clipboard operation
AWS-CLIWrapper copied to clipboard

package AWS::CLIWrapper;

use 5.008001; use strict; use warnings;

our $VERSION = '1.27';

use version; use JSON 2; use IPC::Cmd; use String::ShellQuote; use Carp;

our $Error = { Message => '', Code => '' };

our $true = do { bless (my $dummy = 1), "AWS::CLIWrapper::Boolean" }; our $false = do { bless (my $dummy = 0), "AWS::CLIWrapper::Boolean" };

my $AWSCLI_VERSION = undef; my $DEFAULT_CATCH_ERROR_RETRIES = 3; my $DEFAULT_CATCH_ERROR_MIN_DELAY = 3; my $DEFAULT_CATCH_ERROR_MAX_DELAY = 10;

sub new { my($class, %param) = @_;

my $region = $param{region};

my @opt = ();
for my $k (qw(region profile endpoint_url)) {
    if (my $v = delete $param{$k}) {
        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) = @_; return $self->{awscli_path}; }

sub awscli_version { my ($self) = @_; unless (defined $AWSCLI_VERSION) { $AWSCLI_VERSION = do { my $awscli_path = $self->awscli_path; my $vs = qx($awscli_path --version 2>&1) || ''; my $v; if ($vs =~ m{/([0-9.]+)\s}) { $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;
$k = '--'.$k;

my $type = ref $v;
if (! $type) {
    if ($k eq '--output-file') {
        # aws s3api get-object takes a single arg for output file path
        return $v;
    } else {
        push @v, $v;
    }
} elsif ($type eq 'ARRAY') {
    push @v, map { ref($_) ? encode_json(_compat_kv($_)) : $_ } @$v;
} elsif ($type eq 'HASH') {
    push @v, encode_json(_compat_kv($v));
} elsif ($type eq 'AWS::CLIWrapper::Boolean') {
    if ($$v == 1) {
        return ($k);
    } else {
        return ();
    }
} else {
    push @v, $v;
}

return ($k, @v);

}

>= 0.14.0 : Key, Values, Value, Name

< 0.14.0 : key, values, value, name

sub _compat_kv_uc { my $v = shift; my $type = ref $v;

if ($type && $type eq 'HASH') {
    for my $hk (keys %$v) {
        if ($hk =~ /^(?:key|name|values|value)$/) {
            $v->{ucfirst($hk)} = delete $v->{$hk};
        }
    }
}

return $v;

}

sub _compat_kv_lc {

my $v = shift;

my $type = ref $v;

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') { push(@cmd, shift @); } if (ref($[0]) eq 'ARRAY') { # for s3 sync FROM TO push @cmd, @{ shift @ }; } my($param, %opt) = @_;

if ($service eq 'ec2' && $operation eq 'run-instances') {
    # compat: ec2 run-instances
    # >= 0.14.0 : --count N or --count MIN:MAX
    # <  0.14.0 : --min-count N and --max-count N
    if ($self->awscli_version >= 0.14.0) {
        my($min,$max) = (1,1);
        for my $hk (keys %$param) {
            if ($hk eq 'min_count') {
                $min = delete $param->{min_count};
            } elsif ($hk eq 'max_count') {
                $max = delete $param->{max_count};
            }
        }
        $param->{count} = "${min}:${max}" unless $param->{count}
    } else {
        my($min,$max);
        for my $hk (keys %$param) {
            if ($hk eq 'count') {
                ($min,$max) = split /:/, delete($param->{count});
                $max ||= $min;
                last;
            }
        }
        $param->{min_count} = $min unless $param->{min_count};
        $param->{max_count} = $max unless $param->{max_count};
    }
} elsif ($service eq 's3' && $self->awscli_version >= 0.15.0) {
    if ($operation !~ /^(?:cp|ls|mb|mv|rb|rm|sync|website)$/) {
        return $self->s3api($operation, @_);
    }
} elsif ($service eq 's3api' && $self->awscli_version < 0.15.0) {
    return $self->s3($operation, @_);
}

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($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', @) } sub codecommit { shift->execute('codecommit', @) } sub codeguru_reviewer { shift->execute('codeguru-reviewer', @) } sub codeguru_security { shift->execute('codeguru-security', @) } sub codeguruprofiler { shift->execute('codeguruprofiler', @) } sub codepipeline { shift->execute('codepipeline', @) } sub codestar { shift->execute('codestar', @) } sub codestar_connections { shift->execute('codestar-connections', @) } sub codestar_notifications { shift->execute('codestar-notifications', @) } sub cognito_identity { shift->execute('cognito-identity', @) } sub cognito_idp { shift->execute('cognito-idp', @) } sub cognito_sync { shift->execute('cognito-sync', @) } sub comprehend { shift->execute('comprehend', @) } sub comprehendmedical { shift->execute('comprehendmedical', @) } sub compute_optimizer { shift->execute('compute-optimizer', @) } sub configservice { shift->execute('configservice', @) } sub configure { shift->execute('configure', @) } sub connect { shift->execute('connect', @) } sub connect_contact_lens { shift->execute('connect-contact-lens', @) } sub connectcampaigns { shift->execute('connectcampaigns', @) } sub connectcases { shift->execute('connectcases', @) } sub connectparticipant { shift->execute('connectparticipant', @) } sub controltower { shift->execute('controltower', @) } sub cur { shift->execute('cur', @) } sub customer_profiles { shift->execute('customer-profiles', @) } sub databrew { shift->execute('databrew', @) } sub dataexchange { shift->execute('dataexchange', @) } sub datapipeline { shift->execute('datapipeline', @) } sub datasync { shift->execute('datasync', @) } sub dax { shift->execute('dax', @) } sub deploy { shift->execute('deploy', @) } sub detective { shift->execute('detective', @) } sub devicefarm { shift->execute('devicefarm', @) } sub devops_guru { shift->execute('devops-guru', @) } sub directconnect { shift->execute('directconnect', @) } sub discovery { shift->execute('discovery', @) } sub dlm { shift->execute('dlm', @) } sub dms { shift->execute('dms', @) } sub docdb { shift->execute('docdb', @) } sub docdb_elastic { shift->execute('docdb-elastic', @) } sub drs { shift->execute('drs', @) } sub ds { shift->execute('ds', @) } sub dynamodb { shift->execute('dynamodb', @) } sub dynamodbstreams { shift->execute('dynamodbstreams', @) } sub ebs { shift->execute('ebs', @) } sub ec2 { shift->execute('ec2', @) } sub ec2_instance_connect { shift->execute('ec2-instance-connect', @) } sub ecr { shift->execute('ecr', @) } sub ecr_public { shift->execute('ecr-public', @) } sub ecs { shift->execute('ecs', @) } sub efs { shift->execute('efs', @) } sub eks { shift->execute('eks', @) } sub elastic_inference { shift->execute('elastic-inference', @) } sub elasticache { shift->execute('elasticache', @) } sub elasticbeanstalk { shift->execute('elasticbeanstalk', @) } sub elastictranscoder { shift->execute('elastictranscoder', @) } sub elb { shift->execute('elb', @) } sub elbv2 { shift->execute('elbv2', @) } sub emr { shift->execute('emr', @) } sub emr_containers { shift->execute('emr-containers', @) } sub emr_serverless { shift->execute('emr-serverless', @) } sub es { shift->execute('es', @) } sub events { shift->execute('events', @) } sub evidently { shift->execute('evidently', @) } sub finspace { shift->execute('finspace', @) } sub finspace_data { shift->execute('finspace-data', @) } sub firehose { shift->execute('firehose', @) } sub fis { shift->execute('fis', @) } sub fms { shift->execute('fms', @) } sub forecast { shift->execute('forecast', @) } sub forecastquery { shift->execute('forecastquery', @) } sub frauddetector { shift->execute('frauddetector', @) } sub fsx { shift->execute('fsx', @) } sub gamelift { shift->execute('gamelift', @) } sub gamesparks { shift->execute('gamesparks', @) } sub glacier { shift->execute('glacier', @) } sub globalaccelerator { shift->execute('globalaccelerator', @) } sub glue { shift->execute('glue', @) } sub grafana { shift->execute('grafana', @) } sub greengrass { shift->execute('greengrass', @) } sub greengrassv2 { shift->execute('greengrassv2', @) } sub groundstation { shift->execute('groundstation', @) } sub guardduty { shift->execute('guardduty', @) } sub health { shift->execute('health', @) } sub healthlake { shift->execute('healthlake', @) } sub history { shift->execute('history', @) } sub honeycode { shift->execute('honeycode', @) } sub iam { shift->execute('iam', @) } sub identitystore { shift->execute('identitystore', @) } sub imagebuilder { shift->execute('imagebuilder', @) } sub importexport { shift->execute('importexport', @) } sub inspector { shift->execute('inspector', @) } sub inspector2 { shift->execute('inspector2', @) } sub internetmonitor { shift->execute('internetmonitor', @) } sub iot { shift->execute('iot', @) } sub iot_data { shift->execute('iot-data', @) } sub iot_jobs_data { shift->execute('iot-jobs-data', @) } sub iot_roborunner { shift->execute('iot-roborunner', @) } sub iot1click_devices { shift->execute('iot1click-devices', @) } sub iot1click_projects { shift->execute('iot1click-projects', @) } sub iotanalytics { shift->execute('iotanalytics', @) } sub iotdeviceadvisor { shift->execute('iotdeviceadvisor', @) } sub iotevents { shift->execute('iotevents', @) } sub iotevents_data { shift->execute('iotevents-data', @) } sub iotfleethub { shift->execute('iotfleethub', @) } sub iotfleetwise { shift->execute('iotfleetwise', @) } sub iotsecuretunneling { shift->execute('iotsecuretunneling', @) } sub iotsitewise { shift->execute('iotsitewise', @) } sub iotthingsgraph { shift->execute('iotthingsgraph', @) } sub iottwinmaker { shift->execute('iottwinmaker', @) } sub iotwireless { shift->execute('iotwireless', @) } sub ivs { shift->execute('ivs', @) } sub ivs_realtime { shift->execute('ivs-realtime', @) } sub ivschat { shift->execute('ivschat', @) } sub kafka { shift->execute('kafka', @) } sub kafkaconnect { shift->execute('kafkaconnect', @) } sub kendra { shift->execute('kendra', @) } sub kendra_ranking { shift->execute('kendra-ranking', @) } sub keyspaces { shift->execute('keyspaces', @) } sub kinesis { shift->execute('kinesis', @) } sub kinesis_video_archived_media { shift->execute('kinesis-video-archived-media', @) } sub kinesis_video_media { shift->execute('kinesis-video-media', @) } sub kinesis_video_signaling { shift->execute('kinesis-video-signaling', @) } sub kinesis_video_webrtc_storage { shift->execute('kinesis-video-webrtc-storage', @) } sub kinesisanalytics { shift->execute('kinesisanalytics', @) } sub kinesisanalyticsv2 { shift->execute('kinesisanalyticsv2', @) } sub kinesisvideo { shift->execute('kinesisvideo', @) } sub kms { shift->execute('kms', @) } sub lakeformation { shift->execute('lakeformation', @) } sub lambda { shift->execute('lambda', @) } sub lex_models { shift->execute('lex-models', @) } sub lex_runtime { shift->execute('lex-runtime', @) } sub lexv2_models { shift->execute('lexv2-models', @) } sub lexv2_runtime { shift->execute('lexv2-runtime', @) } sub license_manager { shift->execute('license-manager', @) } sub license_manager_linux_subscriptions { shift->execute('license-manager-linux-subscriptions', @) } sub license_manager_user_subscriptions { shift->execute('license-manager-user-subscriptions', @) } sub lightsail { shift->execute('lightsail', @) } sub location { shift->execute('location', @) } sub logs { shift->execute('logs', @) } sub lookoutequipment { shift->execute('lookoutequipment', @) } sub lookoutmetrics { shift->execute('lookoutmetrics', @) } sub lookoutvision { shift->execute('lookoutvision', @) } sub m2 { shift->execute('m2', @) } sub machinelearning { shift->execute('machinelearning', @) } sub macie { shift->execute('macie', @) } sub macie2 { shift->execute('macie2', @) } sub managedblockchain { shift->execute('managedblockchain', @) } sub marketplace_catalog { shift->execute('marketplace-catalog', @) } sub marketplace_entitlement { shift->execute('marketplace-entitlement', @) } sub marketplacecommerceanalytics { shift->execute('marketplacecommerceanalytics', @) } sub mediaconnect { shift->execute('mediaconnect', @) } sub mediaconvert { shift->execute('mediaconvert', @) } sub medialive { shift->execute('medialive', @) } sub mediapackage { shift->execute('mediapackage', @) } sub mediapackage_vod { shift->execute('mediapackage-vod', @) } sub mediapackagev2 { shift->execute('mediapackagev2', @) } sub mediastore { shift->execute('mediastore', @) } sub mediastore_data { shift->execute('mediastore-data', @) } sub mediatailor { shift->execute('mediatailor', @) } sub memorydb { shift->execute('memorydb', @) } sub meteringmarketplace { shift->execute('meteringmarketplace', @) } sub mgh { shift->execute('mgh', @) } sub mgn { shift->execute('mgn', @) } sub migration_hub_refactor_spaces { shift->execute('migration-hub-refactor-spaces', @) } sub migrationhub_config { shift->execute('migrationhub-config', @) } sub migrationhuborchestrator { shift->execute('migrationhuborchestrator', @) } sub migrationhubstrategy { shift->execute('migrationhubstrategy', @) } sub mobile { shift->execute('mobile', @) } sub mq { shift->execute('mq', @) } sub mturk { shift->execute('mturk', @) } sub mwaa { shift->execute('mwaa', @) } sub neptune { shift->execute('neptune', @) } sub network_firewall { shift->execute('network-firewall', @) } sub networkmanager { shift->execute('networkmanager', @) } sub nimble { shift->execute('nimble', @) } sub oam { shift->execute('oam', @) } sub omics { shift->execute('omics', @) } sub opensearch { shift->execute('opensearch', @) } sub opensearchserverless { shift->execute('opensearchserverless', @) } sub opsworks { shift->execute('opsworks', @) } sub opsworks_cm { shift->execute('opsworks-cm', @) } sub organizations { shift->execute('organizations', @) } sub osis { shift->execute('osis', @) } sub outposts { shift->execute('outposts', @) } sub panorama { shift->execute('panorama', @) } sub payment_cryptography { shift->execute('payment-cryptography', @) } sub payment_cryptography_data { shift->execute('payment-cryptography-data', @) } sub personalize { shift->execute('personalize', @) } sub personalize_events { shift->execute('personalize-events', @) } sub personalize_runtime { shift->execute('personalize-runtime', @) } sub pi { shift->execute('pi', @) } sub pinpoint { shift->execute('pinpoint', @) } sub pinpoint_email { shift->execute('pinpoint-email', @) } sub pinpoint_sms_voice { shift->execute('pinpoint-sms-voice', @) } sub pinpoint_sms_voice_v2 { shift->execute('pinpoint-sms-voice-v2', @) } sub pipes { shift->execute('pipes', @) } sub polly { shift->execute('polly', @) } sub pricing { shift->execute('pricing', @) } sub privatenetworks { shift->execute('privatenetworks', @) } sub proton { shift->execute('proton', @) } sub qldb { shift->execute('qldb', @) } sub qldb_session { shift->execute('qldb-session', @) } sub quicksight { shift->execute('quicksight', @) } sub ram { shift->execute('ram', @) } sub rbin { shift->execute('rbin', @) } sub rds { shift->execute('rds', @) } sub rds_data { shift->execute('rds-data', @) } sub redshift { shift->execute('redshift', @) } sub redshift_data { shift->execute('redshift-data', @) } sub redshift_serverless { shift->execute('redshift-serverless', @) } sub rekognition { shift->execute('rekognition', @) } sub resiliencehub { shift->execute('resiliencehub', @) } sub resource_explorer_2 { shift->execute('resource-explorer-2', @) } sub resource_groups { shift->execute('resource-groups', @) } sub resourcegroupstaggingapi { shift->execute('resourcegroupstaggingapi', @) } sub robomaker { shift->execute('robomaker', @) } sub rolesanywhere { shift->execute('rolesanywhere', @) } sub route53 { shift->execute('route53', @) } sub route53_recovery_cluster { shift->execute('route53-recovery-cluster', @) } sub route53_recovery_control_config { shift->execute('route53-recovery-control-config', @) } sub route53_recovery_readiness { shift->execute('route53-recovery-readiness', @) } sub route53domains { shift->execute('route53domains', @) } sub route53resolver { shift->execute('route53resolver', @) } sub rum { shift->execute('rum', @) } sub s3 { shift->execute('s3', @) } sub s3api { shift->execute('s3api', @) } sub s3control { shift->execute('s3control', @) } sub s3outposts { shift->execute('s3outposts', @) } sub sagemaker { shift->execute('sagemaker', @) } sub sagemaker_a2i_runtime { shift->execute('sagemaker-a2i-runtime', @) } sub sagemaker_edge { shift->execute('sagemaker-edge', @) } sub sagemaker_featurestore_runtime { shift->execute('sagemaker-featurestore-runtime', @) } sub sagemaker_geospatial { shift->execute('sagemaker-geospatial', @) } sub sagemaker_metrics { shift->execute('sagemaker-metrics', @) } sub sagemaker_runtime { shift->execute('sagemaker-runtime', @) } sub savingsplans { shift->execute('savingsplans', @) } sub scheduler { shift->execute('scheduler', @) } sub schemas { shift->execute('schemas', @) } sub sdb { shift->execute('sdb', @) } sub secretsmanager { shift->execute('secretsmanager', @) } sub securityhub { shift->execute('securityhub', @) } sub securitylake { shift->execute('securitylake', @) } sub serverlessrepo { shift->execute('serverlessrepo', @) } sub service_quotas { shift->execute('service-quotas', @) } sub servicecatalog { shift->execute('servicecatalog', @) } sub servicecatalog_appregistry { shift->execute('servicecatalog-appregistry', @) } sub servicediscovery { shift->execute('servicediscovery', @) } sub ses { shift->execute('ses', @) } sub sesv2 { shift->execute('sesv2', @) } sub shield { shift->execute('shield', @) } sub signer { shift->execute('signer', @) } sub simspaceweaver { shift->execute('simspaceweaver', @) } sub sms { shift->execute('sms', @) } sub snow_device_management { shift->execute('snow-device-management', @) } sub snowball { shift->execute('snowball', @) } sub sns { shift->execute('sns', @) } sub sqs { shift->execute('sqs', @) } sub ssm { shift->execute('ssm', @) } sub ssm_contacts { shift->execute('ssm-contacts', @) } sub ssm_incidents { shift->execute('ssm-incidents', @) } sub ssm_sap { shift->execute('ssm-sap', @) } sub sso { shift->execute('sso', @) } 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($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($operation:Str, $param:HashRef, %opt:Hash)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

=item B($operation:Str, $path:ArrayRef, $param:HashRef, %opt:Hash)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

=item B($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,
   })

Special case: several OPERATIONs take a single arg. For example "aws s3api get-object ... output_file". In this case, You can specify below using C<output_file> key:

my $res = $aws->s3api('get-object', {
    bucket      => 'my-bucket',
    key         => 'blahblahblah',
    output_file => '/path/to/output/file',
})

Special case: s3 OPERATION takes one or two arguments in addition to options. For example "aws s3 cp LocalPath s3://S3Path". Pass an extra ARRAYREF to the s3 method in this case:

my $res = $aws->s3('cp', ['LocalPath', 's3://S3Path'], {
    exclude     => '*.bak',
})

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 or C 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)

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

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.

=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 Ehirose31 at gmail.comE

=head1 REPOSITORY

Lhttps://github.com/hirose31/AWS-CLIWrapper

git clone git://github.com/hirose31/AWS-CLIWrapper.git

patches and collaborators are welcome.

=head1 SEE ALSO

Lhttp://aws.amazon.com/cli/, Lhttps://github.com/aws/aws-cli, Lhttp://docs.aws.amazon.com/AWSEC2/latest/APIReference/Welcome.html, Lhttps://github.com/boto/botocore,

=head1 LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

=cut

for Emacsen

Local Variables:

mode: cperl

cperl-indent-level: 4

indent-tabs-mode: nil

coding: utf-8

End:

vi: set ts=4 sw=4 sts=0 et ft=perl fenc=utf-8 ff=unix :