view release on metacpan or search on metacpan
#!/usr/bin/perl
use strict;
use warnings;
use AWS::Lambda::Quick (
name => 'hello-world',
);
sub handler {
my $data = shift;
my $name = $data->{queryStringParameters}{who} // "World";
return {
statusCode => 200,
headers => {
'Content-Type' => 'text/plain',
},
body => "Hello, $name",
};
}
use strict;
use warnings;
use JSON::PP;
use AWS::Lambda::Quick (
name => 'echo',
);
sub handler {
my $data = shift;
return {
statusCode => 200,
headers => {
'Content-Type' => 'application/json',
},
body => encode_json($data),
};
}
requires "AWS::CLIWrapper" => "0";
requires "Archive::Zip" => "0";
requires "File::Temp" => "0";
requires "JSON::PP" => "0";
requires "Mo" => "0";
requires "Path::Tiny" => "0";
requires "autodie" => "0";
requires "strict" => "0";
requires "warnings" => "0";
on 'test' => sub {
requires "Exporter" => "0";
requires "ExtUtils::MakeMaker" => "0";
requires "File::Spec" => "0";
requires "FindBin" => "0";
requires "HTTP::Tiny" => "0";
requires "Test2::V0" => "0";
requires "Test::More" => "1.302015";
requires "Test::TempDir::Tiny" => "0";
requires "base" => "0";
requires "lib" => "0";
};
on 'test' => sub {
recommends "CPAN::Meta" => "2.120900";
};
on 'configure' => sub {
requires "ExtUtils::MakeMaker" => "0";
};
on 'develop' => sub {
requires "Code::TidyAll::Plugin::Test::Vars" => "0.02";
requires "File::Spec" => "0";
requires "IO::Handle" => "0";
requires "IPC::Open3" => "0";
requires "Parallel::ForkManager" => "1.19";
requires "Perl::Critic" => "1.126";
requires "Perl::Tidy" => "20160302";
requires "Pod::Wordlist" => "0";
requires "Test::CPAN::Changes" => "0.19";
requires "Test::CPAN::Meta::JSON" => "0.16";
lib/AWS/Lambda/Quick.pm view on Meta::CPAN
package AWS::Lambda::Quick;
use strict;
use warnings;
use autodie;
our $VERSION = '1.0002';
use AWS::Lambda::Quick::Processor ();
sub import {
shift;
# where's the source code of the script calling us?
my ( undef, $file, undef ) = caller;
# process the whole thing
my $proc = AWS::Lambda::Quick::Processor->new(
src_filename => $file,
@_,
);
lib/AWS/Lambda/Quick.pm view on Meta::CPAN
#!/usr/bin/perl
use strict;
use warnings;
use AWS::Lambda::Quick (
name => 'hello-world',
);
sub handler {
my $data = shift;
my $name = $data->{queryStringParameters}{who} // "World";
return {
statusCode => 200,
headers => {
'Content-Type' => 'text/plain',
},
body => "Hello, $name",
};
}
lib/AWS/Lambda/Quick.pm view on Meta::CPAN
use strict;
use warnings;
use JSON::PP;
use AWS::Lambda::Quick (
name => 'echo',
);
sub handler {
my $data = shift;
return {
statusCode => 200,
headers => {
'Content-Type' => 'application/json',
},
body => encode_json($data),
};
}
lib/AWS/Lambda/Quick/CreateZip.pm view on Meta::CPAN
our $VERSION = '1.0002';
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use Path::Tiny qw( path );
has src_filename => required => 1;
has zip_filename => required => 1;
has extra_files => default => [];
has _src_path => sub { path( shift->src_filename ) };
has _src_dir => sub { shift->_src_path->parent };
has _zip_class => default => 'Archive::Zip';
has _zip => sub { shift->_zip_class->new };
has _script_src => sub { shift->_src_path->slurp_raw };
# this is the same src as in script src but the first occurance of
# "use AWS::Lambda::Quick" is prepended with
# "$INC{'AWS/Lambda/Quick.pm'}=1" to prevent it actually being loaded
# from disk. Note this happens on just one line to avoid screwing
# with line numebrs that could mess with error messages
has _converted_src => sub {
my $self = shift;
my $src = $self->_script_src;
$src =~ s{(?=use AWS::Lambda::Quick(?:\s|[;(]))}
{BEGIN{\$INC{'AWS/Lambda/Quick.pm'}=1} };
return $src;
};
### methods for interfacing with Archive::Zip
### no code outside this section should directly interact with the
### zip file
sub _add_string {
my $self = shift;
my $string = shift;
my $filename = shift;
my $zip = $self->_zip;
my $string_member = $zip->addString( $string, $filename );
$string_member->desiredCompressionMethod(COMPRESSION_DEFLATED);
return ();
}
sub _add_path {
my $self = shift;
my $path = path(shift);
if ( $path->is_absolute ) {
die "Cannot add absolute path! $path";
}
my $abs_path = path( $self->_src_dir, $path );
# silently ignore files that don't exist. This allows you
# to say put extra_files => [qw( lib )] in your file and not
lib/AWS/Lambda/Quick/CreateZip.pm view on Meta::CPAN
return () unless -d $abs_path;
my $iter = $abs_path->iterator;
while ( my $next = $iter->() ) {
my $child = $path->child( $next->basename );
$self->_add_path($child);
}
return ();
}
sub _write_zip {
my $self = shift;
unless ( $self->_zip->writeToFileNamed( $self->zip_filename->stringify )
== AZ_OK ) {
die 'write error';
}
return ();
}
### logic for building the zip file contents ###
sub _build_zip {
my $self = shift;
$self->_add_string( $self->_converted_src, 'handler.pl' );
$self->_add_path($_) for @{ $self->extra_files };
return ();
}
sub create_zip {
my $self = shift;
$self->_build_zip;
$self->_write_zip;
return ();
}
1;
__END__
lib/AWS/Lambda/Quick/Processor.pm view on Meta::CPAN
has src_filename => required => 1;
has 'description';
has 'extra_files';
has 'extra_layers';
has 'memory_size';
has 'region';
has 'stage_name';
has 'timeout';
has _tempdir => sub {
return tempdir( CLEANUP => 1 );
};
has zip_filename => sub {
return path( shift->_tempdir, 'handler.zip' );
};
sub selfkv {
my $self = shift;
my @computed_args;
for my $key (@_) {
my $val = $self->$key;
push @computed_args, $key => $val if defined $val;
}
return @computed_args;
}
sub process {
my $self = shift;
AWS::Lambda::Quick::CreateZip->new(
$self->selfkv(
qw(
extra_files
src_filename
zip_filename
)
),
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
has extra_layers => default => [];
has region => default => 'us-east-1';
has memory_size => default => 128; # this is the AWS default
has timeout => default => 3; # this is the AWS default
has description => default => 'A Perl AWS::Lambda::Quick Lambda function.';
has stage_name => default => 'quick';
### lambda function computed attributes
has aws => sub {
my $self = shift;
return AWS::CLIWrapper->new(
region => $self->region,
);
};
has zip_file_blob => sub { 'fileb://' . shift->zip_filename };
# should we create the function from scratch or just update it?
# by default we interogate the api to see if it exists already
has update_type => sub {
my $self = shift;
my $aws = $self->aws;
my $result = $aws->lambda(
'get-function',
{
'function-name' => $self->name,
}
);
return $result ? 'update-function' : 'create-function';
};
### role attributes
has role => default => 'perl-aws-lambda-quick';
has _role_arn => sub {
my $self = shift;
# if whatever we were passed in role was an actual ARN then we
# can just use that without any further lookups
if ( $self->role
=~ /^arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role\/?[a-zA-Z_0-9+=,.@\-_\/]+$/
) {
$self->debug('using passed role arn');
return $self->role;
}
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
'role-name' => $self->role,
}
);
$self->debug('permissions attached to role');
return $result->{Role}{Arn};
};
### rest api attributes
has rest_api => default => 'perl-aws-lambda-quick';
has rest_api_id => sub {
my $self = shift;
# search existing apis
$self->debug('searching for existing rest api');
my $result = $self->aws_do(
'apigateway',
'get-rest-apis',
);
for ( @{ $result->{items} } ) {
next unless $_->{name} eq $self->rest_api;
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
{
name => $self->rest_api,
description =>
'Created by AWS::Lambda::Quick. See https://metacpan.org/pod/AWS::Lambda::Quick for more info.',
},
);
$self->debug('created new rest api');
return $result->{id};
};
has resource_id => sub {
my $self = shift;
# TODO: We shold probably make this configurable, right?
my $path = '/' . $self->name;
# search existing resources
$self->debug('searching of existing resource');
my $result = $self->aws_do(
'apigateway',
'get-resources',
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
{
'rest-api-id' => $self->rest_api_id,
'parent-id' => $parent_id,
'path-part' => $self->name,
},
);
$self->debug('created new resource');
return $result->{id};
};
has greedy_resource_id => sub {
my $self = shift;
my $path = '/' . $self->name . '/{proxy+}';
# search existing resources
$self->debug('searching of existing greedy resource');
my $result = $self->aws_do(
'apigateway',
'get-resources',
{
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
'parent-id' => $self->resource_id,
'path-part' => '{proxy+}',
},
);
$self->debug('created new greedy resource');
return $result->{id};
};
### methods
sub upload {
my $self = shift;
my $function_arn = $self->_upload_function;
for my $resource_id ( $self->resource_id, $self->greedy_resource_id ) {
$self->_create_method($resource_id);
$self->_create_method_response($resource_id);
$self->_create_integration( $function_arn, $resource_id );
$self->_create_integration_response($resource_id);
}
$self->_stage;
return ();
}
sub api_url {
my $self = shift;
return
'https://'
. $self->rest_api_id
. '.execute-api.'
. $self->region
. '.amazonaws.com/'
. $self->stage_name . '/'
. $self->name;
}
sub _stage {
my $self = shift;
$self->aws_do(
'apigateway',
'create-deployment',
{
'rest-api-id' => $self->rest_api_id,
'stage-name' => $self->stage_name,
}
);
}
sub _create_method {
my $self = shift;
my $resource_id = shift;
my @identifiers = (
'rest-api-id' => $self->rest_api_id,
'resource-id' => $resource_id,
'http-method' => 'ANY',
);
$self->debug('checking for existing method');
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
{
@identifiers,
'authorization-type' => 'NONE',
},
);
$self->debug('new method put');
return ();
}
sub _create_method_response {
my $self = shift;
my $resource_id = shift;
my $identifiers = {
'rest-api-id' => $self->rest_api_id,
'resource-id' => $resource_id,
'http-method' => 'ANY',
'status-code' => 200,
};
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
$self->aws_do(
'apigateway',
'put-method-response',
$identifiers,
);
$self->debug('new method response put');
return ();
}
sub _create_integration {
my $self = shift;
my $function_arn = shift;
my $resource_id = shift;
my $identifiers = {
'rest-api-id' => $self->rest_api_id,
'resource-id' => $resource_id,
'http-method' => 'ANY',
};
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
'integration-http-method' => 'POST',
'credential' => $self->_role_arn,
uri => $uri,
}
);
$self->debug('new integration put');
return ();
}
sub _create_integration_response {
my $self = shift;
my $resource_id = shift;
my $identifiers = {
'rest-api-id' => $self->rest_api_id,
'resource-id' => $resource_id,
'http-method' => 'ANY',
'status-code' => 200,
};
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
{
%{$identifiers},
'selection-pattern' => q{},
}
);
$self->debug('new integration put');
return ();
}
sub _upload_function {
my $self = shift;
my $update_type = $self->update_type;
my $region = $self->region;
# compute the arn based on the list in the AWS::Lambda 0.0.11
# documentation
my $v = $region eq 'me-south-1' ? 3 : 5;
my $layers = [
"arn:aws:lambda:$region:445285296882:layer:perl-5-30-runtime:$v",
lib/AWS/Lambda/Quick/Upload.pm view on Meta::CPAN
'layers' => $layers,
'timeout' => $self->timeout,
'memory-size' => $self->memory_size,
}
);
$self->debug('function congifuration updated');
return $result->{FunctionArn};
}
# just like $self->aws->$method but throws exception on error
sub aws_do {
my $self = shift;
my $method = shift;
my $aws = $self->aws;
my $result = $aws->$method(@_);
return $result if defined $result;
# uh oh, something went wrong, throw exception
## no critic (ProhibitPackageVars)
my $code = $AWS::CLIWrapper::Error->{Code};
my $message = $AWS::CLIWrapper::Error->{Message};
die "AWS CLI failure when calling $method $_[0] '$code': $message";
}
sub encode_json($) {
return JSON::PP->new->ascii->canonical(1)->allow_nonref(1)->encode(shift);
}
sub debug {
my $self = shift;
return unless $ENV{AWS_LAMBDA_QUICK_DEBUG};
for (@_) {
print STDERR "$_\n" or die "Can't write to fh: $!";
}
return ();
}
sub just_update_function_code {
my $self = shift;
$self->aws_do(
'lambda',
'update-function-code',
{
'function-name' => $self->name,
'zip-file' => $self->zip_file_blob,
},
);
t/00-report-prereqs.t view on Meta::CPAN
# hide optional CPAN::Meta modules from prereq scanner
# and check if they are available
my $cpan_meta = "CPAN::Meta";
my $cpan_meta_pre = "CPAN::Meta::Prereqs";
my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic
# Verify requirements?
my $DO_VERIFY_PREREQS = 1;
sub _max {
my $max = shift;
$max = ( $_ > $max ) ? $_ : $max for @_;
return $max;
}
sub _merge_prereqs {
my ($collector, $prereqs) = @_;
# CPAN::Meta::Prereqs object
if (ref $collector eq $cpan_meta_pre) {
return $collector->with_merged_prereqs(
CPAN::Meta::Prereqs->new( $prereqs )
);
}
# Raw hashrefs
is( $z->contents('handler.pl'), <<'PERL', 'hander.pl was stored ok' );
BEGIN{$INC{'AWS/Lambda/Quick.pm'}=1} use AWS::Lambda::Quick (
name => 'whatever',
extra_files => 'lib',
);
use lib qw(lib);
use Greeting;
use JSON::PP qw( encode_json );
sub handler {
my $data = shift;
return {
statusCode => 200,
headers => {
'Content-Type' => 'text/plain',
},
body => Greeting->greeting( $data->{queryStringParameters}{who} ),
};
}
1;
PERL
is( $z->contents('lib/Greeting.pm'), <<'PERL', 'Greeting.pm was stored ok' );
package Greeting;
sub greeting {
my $class = shift;
my $name = shift;
return "Hello, $name";
}
1;
PERL
done_testing;
t/lib/TestHelper/CreateTestFiles.pm view on Meta::CPAN
use strict;
use warnings;
use Test::TempDir::Tiny qw( tempdir );
use Path::Tiny qw( path );
use base qw(Exporter);
our @EXPORT_OK = qw( populated_tempdir );
sub populated_tempdir {
# make a clean temp dir
my $tempdir = path( tempdir() );
$tempdir->remove_tree if -e $tempdir;
$tempdir->mkpath;
# create the temp files
my $dir = path( $tempdir, 'src' );
$dir->mkpath;
t/lib/TestHelper/CreateTestFiles.pm view on Meta::CPAN
path( $dir, 'handler.pl' )->spew(<<'PERL');
use AWS::Lambda::Quick (
name => 'whatever',
extra_files => 'lib',
);
use lib qw(lib);
use Greeting;
use JSON::PP qw( encode_json );
sub handler {
my $data = shift;
return {
statusCode => 200,
headers => {
'Content-Type' => 'text/plain',
},
body => Greeting->greeting( $data->{queryStringParameters}{who} ),
};
}
1;
PERL
# an example library
path( $dir, 'lib' )->mkpath;
path( $dir, 'lib', 'Greeting.pm' )->spew(<<'PERL');
package Greeting;
sub greeting {
my $class = shift;
my $name = shift;
return "Hello, $name";
}
1;
PERL
return $tempdir;
}
xt/release/cpan-changes.t view on Meta::CPAN
use strict;
use warnings;
# this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012
use Test::More 0.96 tests => 1;
use Test::CPAN::Changes;
subtest 'changes_ok' => sub {
changes_file_ok('Changes');
};