lamby 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/cicd.yml +17 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +25 -0
- data/Dockerfile +12 -0
- data/Gemfile.lock +82 -83
- data/README.md +9 -3
- data/Rakefile +1 -0
- data/bin/_setup +6 -0
- data/bin/_test +6 -0
- data/bin/bootstrap +3 -17
- data/bin/setup +3 -3
- data/bin/test +6 -3
- data/bin/update +2 -2
- data/docker-compose.yml +14 -0
- data/lamby.gemspec +1 -1
- data/lib/lamby.rb +2 -1
- data/lib/lamby/handler.rb +16 -3
- data/lib/lamby/logger.rb +13 -9
- data/lib/lamby/rack.rb +11 -9
- data/lib/lamby/rack_alb.rb +11 -14
- data/lib/lamby/rack_http.rb +80 -0
- data/lib/lamby/{rack_api.rb → rack_rest.rb} +7 -3
- data/lib/lamby/ssm_parameter_store.rb +1 -1
- data/lib/lamby/templates.rake +4 -3
- data/lib/lamby/templates/{application_load_balancer.rb → alb.rb} +1 -1
- data/lib/lamby/templates/{application_load_balancer → alb}/app.rb +0 -0
- data/lib/lamby/templates/{application_load_balancer → alb}/build +1 -1
- data/lib/lamby/templates/{application_load_balancer → alb}/deploy +1 -1
- data/lib/lamby/templates/{application_load_balancer → alb}/template.yaml +1 -1
- data/lib/lamby/templates/{api_gateway.rb → http.rb} +2 -2
- data/lib/lamby/templates/{api_gateway → http}/app.rb +1 -1
- data/lib/lamby/templates/{api_gateway → http}/build +1 -1
- data/lib/lamby/templates/{api_gateway → http}/deploy +1 -1
- data/lib/lamby/templates/http/template.yaml +48 -0
- data/lib/lamby/templates/rest.rb +25 -0
- data/lib/lamby/templates/rest/app.rb +10 -0
- data/lib/lamby/templates/rest/build +23 -0
- data/lib/lamby/templates/rest/deploy +22 -0
- data/lib/lamby/templates/{api_gateway → rest}/template.yaml +2 -2
- data/lib/lamby/templates/shared.rb +3 -1
- data/lib/lamby/version.rb +1 -1
- data/vendor/.keep +0 -0
- metadata +29 -23
- data/.python-version +0 -1
- data/.travis.yml +0 -17
- data/Brewfile +0 -5
- data/Pipfile +0 -13
- data/Pipfile.lock +0 -370
data/docker-compose.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
version: '3.7'
|
2
|
+
services:
|
3
|
+
cicd:
|
4
|
+
build: .
|
5
|
+
environment:
|
6
|
+
- AWS_PROFILE=${AWS_PROFILE-default}
|
7
|
+
- RAILS_ENV=${RAILS_ENV-test}
|
8
|
+
- AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION-us-east-1}
|
9
|
+
- SAM_CLI_TELEMETRY=0
|
10
|
+
- DIDPWD=${PWD}
|
11
|
+
volumes:
|
12
|
+
- ~/.aws:/root/.aws:delegated
|
13
|
+
- .:/var/task:delegated
|
14
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
data/lamby.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency 'bundler'
|
25
25
|
spec.add_development_dependency 'rake'
|
26
26
|
spec.add_development_dependency 'minitest'
|
27
|
+
spec.add_development_dependency 'minitest-focus'
|
27
28
|
spec.add_development_dependency 'mocha'
|
28
29
|
spec.add_development_dependency 'pry'
|
29
|
-
spec.add_development_dependency 'sqlite3'
|
30
30
|
end
|
data/lib/lamby.rb
CHANGED
@@ -6,7 +6,8 @@ require 'lamby/version'
|
|
6
6
|
require 'lamby/sam_helpers'
|
7
7
|
require 'lamby/rack'
|
8
8
|
require 'lamby/rack_alb'
|
9
|
-
require 'lamby/
|
9
|
+
require 'lamby/rack_rest'
|
10
|
+
require 'lamby/rack_http'
|
10
11
|
require 'lamby/debug'
|
11
12
|
require 'lamby/handler'
|
12
13
|
require 'rails/railtie'
|
data/lib/lamby/handler.rb
CHANGED
@@ -44,14 +44,27 @@ module Lamby
|
|
44
44
|
self
|
45
45
|
end
|
46
46
|
|
47
|
+
def base64_encodeable?
|
48
|
+
@headers && (
|
49
|
+
@headers['Content-Transfer-Encoding'] == 'binary' ||
|
50
|
+
@headers['X-Lamby-Base64'] == '1'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def body64
|
55
|
+
Base64.strict_encode64(body)
|
56
|
+
end
|
57
|
+
|
47
58
|
private
|
48
59
|
|
49
60
|
def rack
|
50
61
|
@rack ||= case @options[:rack]
|
51
|
-
when :api
|
52
|
-
Lamby::
|
53
|
-
|
62
|
+
when :rest, :api
|
63
|
+
Lamby::RackRest.new @event, @context
|
64
|
+
when :alb
|
54
65
|
Lamby::RackAlb.new @event, @context
|
66
|
+
else
|
67
|
+
Lamby::RackHttp.new @event, @context
|
55
68
|
end
|
56
69
|
end
|
57
70
|
|
data/lib/lamby/logger.rb
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
require 'logger'
|
2
2
|
|
3
|
-
ENV['
|
3
|
+
unless ENV['LAMBY_TEST']
|
4
4
|
|
5
|
-
|
6
|
-
module Logger
|
5
|
+
ENV['RAILS_LOG_TO_STDOUT'] = '1'
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
module Lamby
|
8
|
+
module Logger
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
args[0] = STDOUT
|
12
|
+
super(*args)
|
13
|
+
end
|
12
14
|
|
15
|
+
end
|
13
16
|
end
|
14
|
-
end
|
15
17
|
|
16
|
-
Logger.prepend Lamby::Logger
|
18
|
+
Logger.prepend Lamby::Logger
|
19
|
+
|
20
|
+
end
|
17
21
|
|
18
22
|
# TODO: Railtie initializer
|
19
23
|
# Rails.application.config.logger = ActiveSupport::TaggedLogging.new(
|
data/lib/lamby/rack.rb
CHANGED
@@ -6,6 +6,7 @@ module Lamby
|
|
6
6
|
LAMBDA_EVENT = 'lambda.event'.freeze
|
7
7
|
LAMBDA_CONTEXT = 'lambda.context'.freeze
|
8
8
|
HTTP_X_REQUESTID = 'HTTP_X_REQUEST_ID'.freeze
|
9
|
+
HTTP_COOKIE = 'HTTP_COOKIE'.freeze
|
9
10
|
|
10
11
|
attr_reader :event, :context
|
11
12
|
|
@@ -22,14 +23,6 @@ module Lamby
|
|
22
23
|
{}
|
23
24
|
end
|
24
25
|
|
25
|
-
def api?
|
26
|
-
false
|
27
|
-
end
|
28
|
-
|
29
|
-
def alb?
|
30
|
-
false
|
31
|
-
end
|
32
|
-
|
33
26
|
def multi_value?
|
34
27
|
false
|
35
28
|
end
|
@@ -70,7 +63,16 @@ module Lamby
|
|
70
63
|
end
|
71
64
|
|
72
65
|
def query_string
|
73
|
-
@query_string ||= event
|
66
|
+
@query_string ||= if event.key?('rawQueryString')
|
67
|
+
event['rawQueryString']
|
68
|
+
elsif event.key?('multiValueQueryStringParameters')
|
69
|
+
query = event['multiValueQueryStringParameters'] || {}
|
70
|
+
query.map do |key, value|
|
71
|
+
value.map{ |v| "#{key}=#{v}" }.join('&')
|
72
|
+
end.flatten.join('&')
|
73
|
+
else
|
74
|
+
event['queryStringParameters'].try(:to_query)
|
75
|
+
end
|
74
76
|
end
|
75
77
|
|
76
78
|
def base64_encoded?
|
data/lib/lamby/rack_alb.rb
CHANGED
@@ -53,20 +53,17 @@ module Lamby
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def headers_multi
|
56
|
-
(event['multiValueHeaders'] || {}).
|
57
|
-
v.is_a?(Array)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
string = query.map do |key, value|
|
68
|
-
value.map{ |v| "#{key}=#{v}" }.join('&')
|
69
|
-
end.flatten.join('&')
|
56
|
+
Hash[(event['multiValueHeaders'] || {}).map do |k,v|
|
57
|
+
if v.is_a?(Array)
|
58
|
+
if k == 'x-forwarded-for'
|
59
|
+
[k, v.join(', ')]
|
60
|
+
else
|
61
|
+
[k, v.first]
|
62
|
+
end
|
63
|
+
else
|
64
|
+
[k,v]
|
65
|
+
end
|
66
|
+
end]
|
70
67
|
end
|
71
68
|
|
72
69
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Lamby
|
2
|
+
class RackHttp < Lamby::Rack
|
3
|
+
|
4
|
+
def response(handler)
|
5
|
+
if handler.base64_encodeable?
|
6
|
+
{ isBase64Encoded: true, body: handler.body64 }
|
7
|
+
else
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def env_base
|
15
|
+
{ ::Rack::REQUEST_METHOD => request_method,
|
16
|
+
::Rack::SCRIPT_NAME => '',
|
17
|
+
::Rack::PATH_INFO => path_info,
|
18
|
+
::Rack::QUERY_STRING => query_string,
|
19
|
+
::Rack::SERVER_NAME => server_name,
|
20
|
+
::Rack::SERVER_PORT => server_port,
|
21
|
+
::Rack::SERVER_PROTOCOL => server_protocol,
|
22
|
+
::Rack::RACK_VERSION => ::Rack::VERSION,
|
23
|
+
::Rack::RACK_URL_SCHEME => 'https',
|
24
|
+
::Rack::RACK_INPUT => StringIO.new(body || ''),
|
25
|
+
::Rack::RACK_ERRORS => $stderr,
|
26
|
+
::Rack::RACK_MULTITHREAD => false,
|
27
|
+
::Rack::RACK_MULTIPROCESS => false,
|
28
|
+
::Rack::RACK_RUNONCE => false,
|
29
|
+
LAMBDA_EVENT => event,
|
30
|
+
LAMBDA_CONTEXT => context
|
31
|
+
}.tap do |env|
|
32
|
+
ct = content_type
|
33
|
+
cl = content_length
|
34
|
+
env['CONTENT_TYPE'] = ct if ct
|
35
|
+
env['CONTENT_LENGTH'] = cl if cl
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def env_headers
|
40
|
+
super.tap do |hdrs|
|
41
|
+
if event['cookies'].present?
|
42
|
+
hdrs[HTTP_COOKIE] = event['cookies'].join('; ')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def request_method
|
48
|
+
event.dig('requestContext', 'http', 'method') || event['httpMethod']
|
49
|
+
end
|
50
|
+
|
51
|
+
# Using custom domain names with v1.0 yields a good `path` parameter sans
|
52
|
+
# stage. However, v2.0 and others do not. So we are just going to remove stage
|
53
|
+
# no matter waht from other places for both.
|
54
|
+
#
|
55
|
+
def path_info
|
56
|
+
stage = event.dig('requestContext', 'stage')
|
57
|
+
spath = event.dig('requestContext', 'http', 'path') || event.dig('requestContext', 'path')
|
58
|
+
spath.sub /\A\/#{stage}/, ''
|
59
|
+
end
|
60
|
+
|
61
|
+
def server_name
|
62
|
+
headers['x-forwarded-host'] ||
|
63
|
+
headers['X-Forwarded-Host'] ||
|
64
|
+
headers['host'] ||
|
65
|
+
headers['Host']
|
66
|
+
end
|
67
|
+
|
68
|
+
def server_port
|
69
|
+
headers['x-forwarded-port'] || headers['X-Forwarded-Port']
|
70
|
+
end
|
71
|
+
|
72
|
+
def server_protocol
|
73
|
+
event.dig('requestContext', 'http', 'protocol') ||
|
74
|
+
event.dig('requestContext', 'protocol') ||
|
75
|
+
'HTTP/1.1'
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/lib/lamby/templates.rake
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
installers = {
|
2
|
-
'API Gateway' => :
|
3
|
-
'
|
2
|
+
'API Gateway (HTTP API)' => :http,
|
3
|
+
'API Gateway (REST API)' => :rest,
|
4
|
+
'Application Load Balancer' => :alb
|
4
5
|
}.freeze
|
5
6
|
|
6
7
|
namespace :lamby do
|
@@ -32,5 +33,5 @@ namespace :lamby do
|
|
32
33
|
end
|
33
34
|
|
34
35
|
desc "Install Lamby files for #{installers.first.first}"
|
35
|
-
task install: 'install:
|
36
|
+
task install: 'install:http'
|
36
37
|
end
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
|
-
$LAMBY_INSTALLER_NAME = '
|
1
|
+
$LAMBY_INSTALLER_NAME = 'http'
|
2
2
|
load 'lamby/templates/shared.rb'
|
3
3
|
|
4
|
-
say '==> Running Lamby API Gateway installer...'
|
4
|
+
say '==> Running Lamby API Gateway (HTTP API) installer...'
|
5
5
|
|
6
6
|
say 'Copying files...'
|
7
7
|
copy_file tpl_file('app.rb'), app_file('app.rb')
|
@@ -0,0 +1,48 @@
|
|
1
|
+
AWSTemplateFormatVersion: '2010-09-09'
|
2
|
+
Transform: AWS::Serverless-2016-10-31
|
3
|
+
Description: APPNAMEHERE Lambda (HTTP API)
|
4
|
+
|
5
|
+
Parameters:
|
6
|
+
|
7
|
+
RailsEnv:
|
8
|
+
Type: String
|
9
|
+
Default: production
|
10
|
+
AllowedValues:
|
11
|
+
- staging
|
12
|
+
- production
|
13
|
+
|
14
|
+
Resources:
|
15
|
+
|
16
|
+
RailsFunction:
|
17
|
+
Type: AWS::Serverless::Function
|
18
|
+
Properties:
|
19
|
+
CodeUri: .
|
20
|
+
Handler: app.handler
|
21
|
+
Runtime: ruby2.7
|
22
|
+
MemorySize: 512
|
23
|
+
Timeout: 30
|
24
|
+
Environment:
|
25
|
+
Variables:
|
26
|
+
RAILS_ENV: !Ref RailsEnv
|
27
|
+
FunctionName: !Join [ '', [ 'APPNAMEHERE-', !Ref RailsEnv, '-', !Ref 'AWS::Region' ] ]
|
28
|
+
Events:
|
29
|
+
RailsApiProxy:
|
30
|
+
Type: HttpApi
|
31
|
+
Properties:
|
32
|
+
ApiId: !Ref RailsApi
|
33
|
+
AutoPublishAlias: live
|
34
|
+
|
35
|
+
RailsApi:
|
36
|
+
Type: AWS::Serverless::HttpApi
|
37
|
+
Properties:
|
38
|
+
StageName: !Ref RailsEnv
|
39
|
+
|
40
|
+
Outputs:
|
41
|
+
|
42
|
+
RailsApiUrl:
|
43
|
+
Description: API Gateway Endpoint
|
44
|
+
Value: !Sub "https://${RailsApi}.execute-api.${AWS::Region}.amazonaws.com/${RailsEnv}/"
|
45
|
+
|
46
|
+
RailsFunctionArn:
|
47
|
+
Description: Lambda ARN
|
48
|
+
Value: !GetAtt RailsFunction.Arn
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$LAMBY_INSTALLER_NAME = 'rest'
|
2
|
+
load 'lamby/templates/shared.rb'
|
3
|
+
|
4
|
+
say '==> Running Lamby API Gateway (REST API) installer...'
|
5
|
+
|
6
|
+
say 'Copying files...'
|
7
|
+
copy_file tpl_file('app.rb'), app_file('app.rb')
|
8
|
+
copy_file tpl_file('template.yaml'), app_file('template.yaml')
|
9
|
+
gsub_file app_file('template.yaml'), /APPNAMEHERE/, appname
|
10
|
+
|
11
|
+
say 'Adding to .gitignore...'
|
12
|
+
FileUtils.touch app_file('.gitignore')
|
13
|
+
append_to_file app_file('.gitignore'), <<-GITIGNORE.strip_heredoc
|
14
|
+
# Lamby
|
15
|
+
/.aws-sam
|
16
|
+
GITIGNORE
|
17
|
+
|
18
|
+
say 'Creating ./bin files for build and deploy...'
|
19
|
+
copy_file tpl_file('build'), app_file('bin/build')
|
20
|
+
chmod app_file('bin/build'), 0755
|
21
|
+
copy_file tpl_file('deploy'), app_file('bin/deploy')
|
22
|
+
chmod app_file('bin/deploy'), 0755
|
23
|
+
gsub_file app_file('bin/deploy'), /APPNAMEHERE/, appname.downcase
|
24
|
+
|
25
|
+
say 'Welcome to AWS Lambda and Rails 🎉', :green
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative 'config/boot'
|
2
|
+
require 'lamby'
|
3
|
+
require_relative 'config/application'
|
4
|
+
require_relative 'config/environment'
|
5
|
+
|
6
|
+
$app = Rack::Builder.new { run Rails.application }.to_app
|
7
|
+
|
8
|
+
def handler(event:, context:)
|
9
|
+
Lamby.handler $app, event, context, rack: :rest
|
10
|
+
end
|