AWS-Lambda

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

0.0.18 2020-06-02T19:54:22Z
    - Perl 5.30.3 and 5.28.3 are released

0.0.17 2020-04-28T10:07:10Z
    - new region Europe (Milan) eu-south-1 is available

0.0.16 2020-04-23T00:23:44Z
    - new region Africa (Cape Town) af-south-1 is available

0.0.15 2020-04-17T11:53:53Z
    - fix syntax error of POD

0.0.14 2020-04-11T11:37:43Z
    - AWS::Lambda::PSGI supports API Gateway v2 now

0.0.13 2020-03-15T00:14:09Z
    - perl 5.30.2 is released

0.0.12 2020-03-11T06:42:11Z
    - bump up AWS::XRay to 0.11

MANIFEST  view on Meta::CPAN

lib/AWS/Lambda/AL2.pm
lib/AWS/Lambda/AL2023.pm
lib/AWS/Lambda/Bootstrap.pm
lib/AWS/Lambda/Context.pm
lib/AWS/Lambda/PSGI.pm
lib/AWS/Lambda/ResponseWriter.pm
minil.toml
script/bootstrap
t/00_compile.t
t/01_echo.t
t/02_error.t
t/03_init_error.t
t/04_handler_not_found.t
t/10_lambda_next.t
t/11_lambda_response.t
t/12_lambda_error.t
t/13_lambda_init_error.t
t/14_streaming.t
t/15_lambda_response_streaming.t
t/20_psgi.t
t/21_psgi_response_streaming.t
t/lib/BootstrapMock.pm
t/test_handlers/echo.pl
t/test_handlers/error.pl
t/test_handlers/init_error.pl
t/test_handlers/streaming.pl
t/testdata/alb-base64-request.json
t/testdata/alb-get-request.json
t/testdata/alb-post-request.json
t/testdata/apigateway-base64-request.json
t/testdata/apigateway-get-request.json
t/testdata/apigateway-post-request.json
t/testdata/apigateway-v2-base64-request.json
t/testdata/apigateway-v2-get-request.json
t/testdata/apigateway-v2-post-request.json

author/publish-perl-runtimes.pl  view on Meta::CPAN

            $pm->start("$region/$perl_version") and next;
            say STDERR "$region/$perl_version: START";
            my $object = head_or_put($region, "perl-$stack-$suffix$arch_suffix.zip", $zip, $md5);
            my $version = $object->{VersionId} // 'UNKNOWN';
            my $stack_name = "lambda-$stack-$suffix$arch_suffix" =~ s/_/-/r;

            say STDERR "deploying stack $stack_name in $region...";
            run_command('aws', '--region', $region, 'cloudformation', 'deploy',
                '--stack-name', $stack_name,
                '--template-file', "$FindBin::Bin/cfn-layer-$suffix-$arch.yml",
                '--parameter-overrides', "PerlVersion=$perl_version", "Name=perl-$stack-$suffix$arch_suffix", "ObjectVersion=$version");
            say STDERR "$region/$perl_version: DONE";
            $pm->finish(0);
        }
    }

    $pm->wait_all_children;
}

if ($force) {
    say STDERR "FORCE TO DEPLOY";

author/update-aws-lambda-al.pl  view on Meta::CPAN

    $layers->{$version}{$region} = $arn;
});

for my $version (@$versions) {
    for my $region (@{$regions->{x86_64}}) {
        say STDERR "loading $version in $region...";
        $pm->start("$version/$region") and next;

        my $runtime_stack = "lambda-@{[ $version =~ s/[.]/-/r ]}-runtime";
        my $paws_stack = "lambda-@{[ $version =~ s/[.]/-/r ]}-paws";
        my ($stdout, $stderr, $exit);

        ($stdout, $stderr, $exit) = capture {
            system("aws --region $region cloudformation describe-stacks --output json --stack-name $runtime_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
        };
        if ($exit != 0) {
            if ($stderr =~ /ValidationError/) {
                # the stack doesn't exist; skip it.
                $pm->finish;
                next;
            }
            die "failed to execute aws cli";
        }
        my $runtime_arn = $stdout;

        ($stdout, $stderr, $exit) = capture {
            system("aws --region $region cloudformation describe-stacks --output json --stack-name $paws_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
        };
        if ($exit != 0) {
            if ($stderr =~ /ValidationError/) {
                # the stack doesn't exist; skip it.
                $pm->finish;
                next;
            }
            die "failed to execute aws cli";
        }
        my $paws_arn = $stdout;
 
        chomp($runtime_arn);
        chomp($paws_arn);

author/update-aws-lambda-al2.pl  view on Meta::CPAN

    $layers_al2_x86_64->{$version}{$region} = $arn;
});

for my $version (@$versions_al2) {
    for my $region (@{$regions->{x86_64}}) {
        say STDERR "loading $version in $region...";
        $pm_al2_x86_64->start("$version/$region") and next;

        my $runtime_stack = "lambda-$version-runtime-al2" =~ s/[._]/-/gr;
        my $paws_stack = "lambda-$version-paws-al2" =~ s/[._]/-/gr;
        my ($stdout, $stderr, $exit);

        ($stdout, $stderr, $exit) = capture {
            system("aws --region $region cloudformation describe-stacks --output json --stack-name $runtime_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
        };
        if ($exit != 0) {
            if ($stderr =~ /ValidationError/) {
                # the stack doesn't exist; skip it.
                $pm_al2_x86_64->finish;
                next;
            }
            die "failed to execute aws cli";
        }
        my $runtime_arn = $stdout;

        ($stdout, $stderr, $exit) = capture {
            system("aws --region $region cloudformation describe-stacks --output json --stack-name $paws_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
        };
        if ($exit != 0) {
            if ($stderr =~ /ValidationError/) {
                # the stack doesn't exist; skip it.
                $pm_al2_x86_64->finish;
                next;
            }
            die "failed to execute aws cli";
        }
        my $paws_arn = $stdout;
 
        chomp($runtime_arn);
        chomp($paws_arn);

author/update-aws-lambda-al2.pl  view on Meta::CPAN

});

for my $version (@$versions_al2) {
    for my $arch (@$archs) {
        for my $region (@{$regions->{$arch}}) {
            say STDERR "loading $version in $region...";
            $pm_al2->start("$version/$region/$arch") and next;

            my $runtime_stack = "lambda-$version-runtime-al2-$arch" =~ s/[._]/-/gr;
            my $paws_stack = "lambda-$version-paws-al2-$arch" =~ s/[._]/-/gr;
            my ($stdout, $stderr, $exit);

            ($stdout, $stderr, $exit) = capture {
                system("aws --region $region cloudformation describe-stacks --output json --stack-name $runtime_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
            };
            if ($exit != 0) {
                if ($stderr =~ /ValidationError/) {
                    # the stack doesn't exist; skip it.
                    $pm_al2->finish;
                    next;
                }
                die "failed to execute aws cli";
            }
            my $runtime_arn = $stdout;

            ($stdout, $stderr, $exit) = capture {
                system("aws --region $region cloudformation describe-stacks --output json --stack-name $paws_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
            };
            if ($exit != 0) {
                if ($stderr =~ /ValidationError/) {
                    # the stack doesn't exist; skip it.
                    $pm_al2->finish;
                    next;
                }
                die "failed to execute aws cli";
            }
            my $paws_arn = $stdout;

            chomp($runtime_arn);
            chomp($paws_arn);

author/update-aws-lambda-al2023.pl  view on Meta::CPAN

});

for my $version (@$versions_al2023) {
    for my $arch (@$archs) {
        for my $region (@{$regions->{$arch}}) {
            say STDERR "loading $version in $region...";
            $pm_al2023->start("$version/$region/$arch") and next;

            my $runtime_stack = "lambda-$version-runtime-al2023-$arch" =~ s/[._]/-/gr;
            my $paws_stack = "lambda-$version-paws-al2023-$arch" =~ s/[._]/-/gr;
            my ($stdout, $stderr, $exit);

            ($stdout, $stderr, $exit) = capture {
                system("aws --region $region cloudformation describe-stacks --output json --stack-name $runtime_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
            };
            if ($exit != 0) {
                if ($stderr =~ /ValidationError/) {
                    # the stack doesn't exist; skip it.
                    $pm_al2023->finish;
                    next;
                }
                die "failed to execute aws cli";
            }
            my $runtime_arn = $stdout;

            ($stdout, $stderr, $exit) = capture {
                system("aws --region $region cloudformation describe-stacks --output json --stack-name $paws_stack | jq -r .Stacks[0].Outputs[0].OutputValue");
            };
            if ($exit != 0) {
                if ($stderr =~ /ValidationError/) {
                    # the stack doesn't exist; skip it.
                    $pm_al2023->finish;
                    next;
                }
                die "failed to execute aws cli";
            }
            my $paws_arn = $stdout;

            chomp($runtime_arn);
            chomp($paws_arn);

author/validate-account.sh  view on Meta::CPAN

#!/usr/bin/env bash

set -xue

AWS_ACCOUNT=$(aws sts get-caller-identity | jq -r .Account)

if [[ "$AWS_ACCOUNT" != 445285296882 ]]; then
    echo "Invalid AWS Account: $AWS_ACCOUNT" > /dev/stderr
    exit 2
fi

examples/cgi/WwwCounter/readme.html  view on Meta::CPAN

変更後:<img src="wwwcount.cgi?hide+neko.gif" 略...>
</pre>
<p>隠しカウンタのカウント数は、レポート機能や、wwwcount.cnt ファイルを直接参照することで確認できます。</p>
</div>

<h4>■ <a name="RefFind">リンク元発見機能</a></h4>
<div class=i>
<p>CGIグラフィックカウンターを以下のように呼び出すと、自分のホームページがどこからリンクされているのか発見することができます。</p>
<pre class=c>
&lt;script&gt;
xx = escape(document.referrer);
yy = "";
for (i = 0; i &lt; xx.length; i++) {
  zz = xx.charAt(i);
  yy += (zz == "+") ? "%2B" : zz;
}
document.write('&lt;img width=96 height=19 ');
document.write('src="wwwcount.cgi?gif');
document.write('+ref+', yy, '"&gt;');
&lt;/script&gt;
&lt;noscript&gt;

examples/cgi/WwwCounter/sample.html  view on Meta::CPAN

<h4>SSIテキストカウンター</h4>
<div class="i">
あなたは <!--#exec cgi="wwwcount.cgi text"--> 人目のお客様です。<br>
(SSI がサポートされている場合のみ表示されます。)
</div>

<h4>リンク元発見機能(CGI版)</h4>
<div class="i">
あなたは
<script>
console.log(document.referrer);
var ref = document.referrer;
ref = ref.replace(/ /, "%20");
ref = ref.replace(/\+/, "%2B");
ref = ref.replace(/\?/, "%3F");
console.log(ref);
document.write("<img width=96 height=18 src='wwwcount.cgi?gif+ref+" + ref + "' alt='counter'>");
</script>
人目のお客様です。
</div>

<h4>隠しカウンター</h4>

examples/s3-get-object/deploy.sh  view on Meta::CPAN

PREFIX=$3

aws cloudformation package \
    --template-file "$ROOT/template.yaml" \
    --output-template-file "$ROOT/packaged.yaml" \
    --s3-bucket "$BUCKET"

aws cloudformation deploy \
    --stack-name "$STACK" \
    --template "$ROOT/packaged.yaml" \
    --parameter-overrides "BucketNamePrefix=$PREFIX"\
    --capabilities CAPABILITY_IAM

lib/AWS/Lambda/Bootstrap.pm  view on Meta::CPAN


    my $task_root = $self->{task_root};
    my $handler = $self->{handler};
    my $name = $self->{function_name};
    return try {
        package main;
        require "${task_root}/${handler}.pl";
        my $f = main->can($name) // die "handler $name is not found";
        $self->{function} = $f;
    } catch {
        $self->lambda_init_error($_);
        $self->{function} = sub {};
        undef;
    };
}

sub handle_event {
    my $self = shift;
    $self->_init or return;
    my ($payload, $context) = $self->lambda_next;
    my $response = try {
        local $AWS::Lambda::context = $context;
        local $ENV{_X_AMZN_TRACE_ID} = $context->{trace_id};
        $self->{function}->($payload, $context);
    } catch {
        my $err = $_;
        print STDERR "$err";
        $self->lambda_error($err, $context);
        bless {}, 'AWS::Lambda::ErrorSentinel';
    };
    my $ref = ref($response);
    if ($ref eq 'AWS::Lambda::ErrorSentinel') {
        return;
    }
    if ($ref eq 'CODE') {
        $self->lambda_response_streaming($response, $context);
    } else {
        $self->lambda_response($response, $context);

lib/AWS/Lambda/Bootstrap.pm  view on Meta::CPAN

        $response->(sub {
            my $content_type = shift;
            $writer = AWS::Lambda::ResponseWriter->new(
                response_url => $url,
                http         => $self->{http},
            );
            $writer->_request($content_type);
            return $writer;
        });
    } catch {
        my $err = $_;
        print STDERR "$err";
        if ($writer) {
            $writer->_close_with_error($err);
        } else {
            $self->lambda_error($err, $context);
        }
    };
    if ($writer) {
        my $response = $writer->_handle_response;
        if (!$response->{success}) {
            die "failed to response of execution: $response->{status} $response->{reason}";
        }
    }
}

sub lambda_error {
    my $self = shift;
    my ($error, $context) = @_;
    my $runtime_api = $self->{runtime_api};
    my $api_version = $self->{api_version};
    my $request_id = $context->aws_request_id;
    my $url = "http://${runtime_api}/${api_version}/runtime/invocation/${request_id}/error";
    my $type = blessed($error) // "Error";
    my $resp = $self->{http}->post($url, {
        content => encode_json({
            errorMessage => "$error",
            errorType => "$type",
        }),
    });
    if (!$resp->{success}) {
        die "failed to send error of execution: $resp->{status} $resp->{reason}";
    }
}

sub lambda_init_error {
    my $self = shift;
    my $error = shift;
    my $runtime_api = $self->{runtime_api};
    my $api_version = $self->{api_version};
    my $url = "http://${runtime_api}/${api_version}/runtime/init/error";
    my $type = blessed($error) // "Error";
    my $resp = $self->{http}->post($url, {
        content => encode_json({
            errorMessage => "$error",
            errorType => "$type",
        }),
    });
    if (!$resp->{success}) {
        die "failed to send error of execution: $resp->{status} $resp->{reason}";
    }
}

1;
__END__

=encoding utf-8

=head1 NAME

lib/AWS/Lambda/PSGI.pm  view on Meta::CPAN

        if ($key !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
            $key = "HTTP_$key";
        }
        if (ref $value eq "ARRAY") {
            $value = join ", ", @$value;
        }
        $env->{$key} = $value;
    }

    $env->{'psgi.version'}      = [1, 1];
    $env->{'psgi.errors'}       = *STDERR;
    $env->{'psgi.run_once'}     = Plack::Util::FALSE;
    $env->{'psgi.multithread'}  = Plack::Util::FALSE;
    $env->{'psgi.multiprocess'} = Plack::Util::FALSE;
    $env->{'psgi.streaming'}    = Plack::Util::FALSE;
    $env->{'psgi.nonblocking'}  = Plack::Util::FALSE;
    $env->{'psgix.harakiri'}    = Plack::Util::TRUE;
    $env->{'psgix.input.buffered'} = Plack::Util::TRUE;

    # inject the request id that compatible with Plack::Middleware::RequestId
    if ($ctx) {

lib/AWS/Lambda/PSGI.pm  view on Meta::CPAN

    while (my ($key, $value) = each %$headers) {
        $key =~ s/-/_/g;
        $key = uc $key;
        if ($key !~ /^(?:CONTENT_LENGTH|CONTENT_TYPE)$/) {
            $key = "HTTP_$key";
        }
        $env->{$key} = $value;
    }

    $env->{'psgi.version'}      = [1, 1];
    $env->{'psgi.errors'}       = *STDERR;
    $env->{'psgi.run_once'}     = Plack::Util::FALSE;
    $env->{'psgi.multithread'}  = Plack::Util::FALSE;
    $env->{'psgi.multiprocess'} = Plack::Util::FALSE;
    $env->{'psgi.streaming'}    = Plack::Util::FALSE;
    $env->{'psgi.nonblocking'}  = Plack::Util::FALSE;
    $env->{'psgix.harakiri'}    = Plack::Util::TRUE;
    $env->{'psgix.input.buffered'} = Plack::Util::TRUE;

    # inject the request id that compatible with Plack::Middleware::RequestId
    if ($ctx) {

lib/AWS/Lambda/ResponseWriter.pm  view on Meta::CPAN

    my $self = shift;
    if ($self->{closed}) {
        # already closed
        return;
    }
    my $handle = $self->{handle};
    $self->{closed} = 1;
    return $handle->write("0\x0D\x0A\x0D\x0A");
}

sub _close_with_error {
    my ($self, $error) = @_;
    if ($self->{closed}) {
        # already closed
        return;
    }
    $self->{closed} = 1;
    my $handle = $self->{handle};
    $handle->write("0\x0D\x0A");
    my $type = blessed($error) // "Error";
    return $handle->write_header_lines({
        "lambda-runtime-function-error-type" => "$type",
        "lambda-runtime-function-error-body" => encode_base64("$error", ""),
    }, {
        "lambda-runtime-function-error-type" => "Lambda-Runtime-Function-Error-Type",
        "lambda-runtime-function-error-body" => "Lambda-Runtime-Function-Error-Body",
    });
}

1;

t/02_error.t  view on Meta::CPAN

use strict;
use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "error.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_next => sub {
        return +{
            key1 => 1,
            key2 => 2,
            key3 => 3,
        }, undef;
    },
    lambda_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/some error/;
done_testing;

t/03_init_error.t  view on Meta::CPAN

use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;
use AWS::Lambda::Context;
use Try::Tiny;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "init_error.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_init_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/did not return a true value/;

done_testing;

t/04_handler_not_found.t  view on Meta::CPAN

use warnings;
use utf8;
use Test::More;

use FindBin;
use lib "$FindBin::Bin/lib";
use BootstrapMock;
use AWS::Lambda::Context;
use Try::Tiny;

my $error;
my $bootstrap = BootstrapMock->new(
    handler     => "echo.handle_not_found",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    lambda_init_error => sub {
        my $self = shift;
        $error = shift;
    },
);

ok !$bootstrap->handle_event;
like $error, qr/handler handle_not_found is not found/;

done_testing;

t/12_lambda_error.t  view on Meta::CPAN

        my $sock = shift;
        my $server = HTTP::Server::PSGI->new(
            listen_sock => $sock,
        );
        $server->run(sub {
            my $env = shift;
            my $req = Plack::Request->new($env);
            is $req->method, "POST", "http method";
            my $body = $req->body;
            my $response = decode_json(<$body>);
            cmp_deeply $response, {errorMessage=>"some error 😨", errorType=>'Error'}, "response";
            my $res = $req->new_response(200);
            $res->finalize;
        });
    },
    max_wait => 10, # seconds
);

my $bootstrap = AWS::Lambda::Bootstrap->new(
    handler     => "echo.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    runtime_api => "127.0.0.1:" . $app_server->port,
);

my $error = "some error 😨";
my $context = AWS::Lambda::Context->new(
    deadline_ms => 1542409706888,
    aws_request_id => "8476a536-e9f4-11e8-9739-2dfe598c3fcd",
    invoked_function_arn => 'arn:aws:lambda:us-east-2:123456789012:function:custom-runtime',
);
$bootstrap->lambda_error($error, $context);
$app_server->stop;

done_testing;

t/13_lambda_init_error.t  view on Meta::CPAN

        my $sock = shift;
        my $server = HTTP::Server::PSGI->new(
            listen_sock => $sock,
        );
        $server->run(sub {
            my $env = shift;
            my $req = Plack::Request->new($env);
            is $req->method, "POST", "http method";
            my $body = $req->body;
            my $response = decode_json(<$body>);
            cmp_deeply $response, {errorMessage=>"some error 😨", errorType=>'Error'}, "response";
            my $res = $req->new_response(200);
            $res->finalize;
        });
    },
    max_wait => 10, # seconds
);

my $bootstrap = AWS::Lambda::Bootstrap->new(
    handler     => "echo.handle",
    runtime_api => "example.com",
    task_root   => "$FindBin::Bin/test_handlers",
    runtime_api => "127.0.0.1:" . $app_server->port,
);

my $error = "some error 😨";
$bootstrap->lambda_init_error($error);
$app_server->stop;

done_testing;

t/lib/BootstrapMock.pm  view on Meta::CPAN


our @ISA = qw(AWS::Lambda::Bootstrap);

sub new {
    my $class = shift;
    my %args = @_;
    my $self = $class->SUPER::new(%args);
    $self->{lambda_next}               = $args{lambda_next}               // sub { die "unexpected call of lambda_next" };
    $self->{lambda_response}           = $args{lambda_response}           // sub { die "unexpected call of lambda_response" };
    $self->{lambda_response_streaming} = $args{lambda_response_streaming} // sub { die "unexpected call of lambda_response_streaming" };
    $self->{lambda_error}              = $args{lambda_error}              // sub { die "unexpected call of lambda_error" };
    $self->{lambda_init_error}         = $args{lambda_init_error}         // sub { die "unexpected call of lambda_init_error" };
    return $self;
}

sub lambda_next {
    my $self = shift;
    return $self->{lambda_next}->($self, @_);
}

sub lambda_response {
    my $self = shift;
    return $self->{lambda_response}->($self, @_);
}

sub lambda_response_streaming {
    my $self = shift;
    return $self->{lambda_response_streaming}->($self, @_);
}

sub lambda_error {
    my $self = shift;
    return $self->{lambda_error}->($self, @_);
}

sub lambda_init_error {
    my $self = shift;
    return $self->{lambda_init_error}->($self, @_);
}

1;

t/test_handlers/error.pl  view on Meta::CPAN

use utf8;
use strict;
use warnings;

sub handle {
    die "some error";
}

1;



( run in 1.116 second using v1.01-cache-2.11-cpan-49f99fa48dc )