lamby 1.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/cicd.yml +17 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +58 -0
- data/Dockerfile +12 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +94 -79
- 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 -2
- data/lib/lamby.rb +7 -4
- data/lib/lamby/debug.rb +8 -1
- data/lib/lamby/handler.rb +16 -3
- data/lib/lamby/logger.rb +13 -9
- data/lib/lamby/rack.rb +21 -9
- data/lib/lamby/rack_alb.rb +12 -15
- data/lib/lamby/rack_http.rb +84 -0
- data/lib/lamby/{rack_api.rb → rack_rest.rb} +7 -3
- data/lib/lamby/ssm_parameter_store.rb +9 -8
- data/lib/lamby/templates.rake +4 -3
- data/lib/lamby/templates/{application_load_balancer.rb → alb.rb} +2 -2
- 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} +3 -3
- 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 -37
- data/.python-version +0 -1
- data/.travis.yml +0 -17
- data/Brewfile +0 -5
- data/Pipfile +0 -13
- data/Pipfile.lock +0 -370
data/bin/setup
CHANGED
data/bin/test
CHANGED
data/bin/update
CHANGED
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
@@ -19,12 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
spec.add_dependency 'rack'
|
22
|
-
spec.add_dependency 'rails'
|
23
22
|
spec.add_development_dependency 'aws-sdk-ssm'
|
24
23
|
spec.add_development_dependency 'bundler'
|
25
24
|
spec.add_development_dependency 'rake'
|
26
25
|
spec.add_development_dependency 'minitest'
|
26
|
+
spec.add_development_dependency 'minitest-focus'
|
27
27
|
spec.add_development_dependency 'mocha'
|
28
28
|
spec.add_development_dependency 'pry'
|
29
|
-
spec.add_development_dependency 'sqlite3'
|
30
29
|
end
|
data/lib/lamby.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
require 'lamby/logger'
|
2
2
|
require 'rack'
|
3
3
|
require 'base64'
|
4
|
-
require 'active_support/all'
|
5
4
|
require 'lamby/version'
|
6
5
|
require 'lamby/sam_helpers'
|
7
6
|
require 'lamby/rack'
|
8
7
|
require 'lamby/rack_alb'
|
9
|
-
require 'lamby/
|
8
|
+
require 'lamby/rack_rest'
|
9
|
+
require 'lamby/rack_http'
|
10
10
|
require 'lamby/debug'
|
11
11
|
require 'lamby/handler'
|
12
|
-
|
13
|
-
|
12
|
+
|
13
|
+
if defined?(Rails)
|
14
|
+
require 'rails/railtie'
|
15
|
+
require 'lamby/railtie'
|
16
|
+
end
|
14
17
|
|
15
18
|
module Lamby
|
16
19
|
|
data/lib/lamby/debug.rb
CHANGED
@@ -6,7 +6,7 @@ module Lamby
|
|
6
6
|
|
7
7
|
def on?(event)
|
8
8
|
params = event['multiValueQueryStringParameters'] || event['queryStringParameters']
|
9
|
-
(
|
9
|
+
(development? || ENV['LAMBY_DEBUG']) && params && params['debug'] == '1'
|
10
10
|
end
|
11
11
|
|
12
12
|
def call(event, context, env)
|
@@ -42,5 +42,12 @@ module Lamby
|
|
42
42
|
HTML
|
43
43
|
end
|
44
44
|
|
45
|
+
def development?
|
46
|
+
ENV
|
47
|
+
.slice('RACK_ENV', 'RAILS_ENV')
|
48
|
+
.values
|
49
|
+
.any? { |v| v.to_s.casecmp('development').zero? }
|
50
|
+
end
|
51
|
+
|
45
52
|
end
|
46
53
|
end
|
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,26 @@ 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
|
+
build_query_string
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_query_string
|
79
|
+
return if event['queryStringParameters'].nil?
|
80
|
+
|
81
|
+
Rack::Utils.build_nested_query(
|
82
|
+
event.fetch('queryStringParameters')
|
83
|
+
)
|
84
|
+
.gsub('[', '%5B')
|
85
|
+
.gsub(']', '%5D')
|
74
86
|
end
|
75
87
|
|
76
88
|
def base64_encoded?
|
data/lib/lamby/rack_alb.rb
CHANGED
@@ -11,7 +11,7 @@ module Lamby
|
|
11
11
|
|
12
12
|
def response(handler)
|
13
13
|
hhdrs = handler.headers
|
14
|
-
multivalue_headers = hhdrs.transform_values { |v| Array.
|
14
|
+
multivalue_headers = hhdrs.transform_values { |v| Array[v].compact.flatten } if multi_value?
|
15
15
|
status_description = "#{handler.status} #{::Rack::Utils::HTTP_STATUS_CODES[handler.status]}"
|
16
16
|
base64_encode = hhdrs['Content-Transfer-Encoding'] == 'binary' || hhdrs['X-Lamby-Base64'] == '1'
|
17
17
|
body = Base64.strict_encode64(handler.body) if base64_encode
|
@@ -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,84 @@
|
|
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 cookies.any?
|
42
|
+
hdrs[HTTP_COOKIE] = 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
|
+
def cookies
|
52
|
+
event['cookies'] || []
|
53
|
+
end
|
54
|
+
|
55
|
+
# Using custom domain names with v1.0 yields a good `path` parameter sans
|
56
|
+
# stage. However, v2.0 and others do not. So we are just going to remove stage
|
57
|
+
# no matter waht from other places for both.
|
58
|
+
#
|
59
|
+
def path_info
|
60
|
+
stage = event.dig('requestContext', 'stage')
|
61
|
+
spath = event.dig('requestContext', 'http', 'path') || event.dig('requestContext', 'path')
|
62
|
+
spath.sub /\A\/#{stage}/, ''
|
63
|
+
end
|
64
|
+
|
65
|
+
def server_name
|
66
|
+
headers['x-forwarded-host'] ||
|
67
|
+
headers['X-Forwarded-Host'] ||
|
68
|
+
headers['host'] ||
|
69
|
+
headers['Host']
|
70
|
+
end
|
71
|
+
|
72
|
+
def server_port
|
73
|
+
headers['x-forwarded-port'] || headers['X-Forwarded-Port']
|
74
|
+
end
|
75
|
+
|
76
|
+
def server_protocol
|
77
|
+
event.dig('requestContext', 'http', 'protocol') ||
|
78
|
+
event.dig('requestContext', 'protocol') ||
|
79
|
+
'HTTP/1.1'
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -19,9 +19,10 @@ module Lamby
|
|
19
19
|
parts = path.from(1).split('/')
|
20
20
|
env = parts.pop
|
21
21
|
path = "/#{parts.join('/')}"
|
22
|
-
new(path).get!.params.detect do |p|
|
22
|
+
param = new(path).get!.params.detect do |p|
|
23
23
|
p.env == env
|
24
|
-
end
|
24
|
+
end
|
25
|
+
param&.value
|
25
26
|
end
|
26
27
|
|
27
28
|
end
|
@@ -32,9 +33,9 @@ module Lamby
|
|
32
33
|
@options = options
|
33
34
|
end
|
34
35
|
|
35
|
-
def to_env
|
36
|
+
def to_env(overwrite: true)
|
36
37
|
params.each do |param|
|
37
|
-
ENV[param.env] = param.value
|
38
|
+
overwrite ? ENV[param.env] = param.value : ENV[param.env] ||= param.value
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -44,7 +45,7 @@ module Lamby
|
|
44
45
|
|
45
46
|
def get!
|
46
47
|
get_all!
|
47
|
-
get_history!
|
48
|
+
get_history! unless label.to_s.empty?
|
48
49
|
self
|
49
50
|
end
|
50
51
|
|
@@ -68,7 +69,7 @@ module Lamby
|
|
68
69
|
|
69
70
|
def dotenv_contents
|
70
71
|
params.each_with_object('') do |param, contents|
|
71
|
-
line = "
|
72
|
+
line = "#{param.env}=#{param.value}\n"
|
72
73
|
contents << line
|
73
74
|
end
|
74
75
|
end
|
@@ -98,7 +99,7 @@ module Lamby
|
|
98
99
|
with_decryption: true,
|
99
100
|
max_results: MAX_RESULTS
|
100
101
|
}.tap { |options|
|
101
|
-
token = @all_response
|
102
|
+
token = @all_response&.next_token
|
102
103
|
options[:next_token] = token if token
|
103
104
|
}
|
104
105
|
end
|
@@ -137,7 +138,7 @@ module Lamby
|
|
137
138
|
with_decryption: true,
|
138
139
|
max_results: MAX_RESULTS
|
139
140
|
}.tap { |options|
|
140
|
-
token = @hist_response
|
141
|
+
token = @hist_response&.next_token
|
141
142
|
options[:next_token] = token if token
|
142
143
|
}
|
143
144
|
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
|
@@ -1,4 +1,4 @@
|
|
1
|
-
$LAMBY_INSTALLER_NAME = '
|
1
|
+
$LAMBY_INSTALLER_NAME = 'alb'
|
2
2
|
load 'lamby/templates/shared.rb'
|
3
3
|
|
4
4
|
say '==> Running Lamby Application Load Balancer installer...'
|
@@ -10,7 +10,7 @@ gsub_file app_file('template.yaml'), /APPNAMEHERE/, appname
|
|
10
10
|
|
11
11
|
say 'Adding to .gitignore...'
|
12
12
|
FileUtils.touch app_file('.gitignore')
|
13
|
-
append_to_file app_file('.gitignore'),
|
13
|
+
append_to_file app_file('.gitignore'), <<~GITIGNORE
|
14
14
|
# Lamby
|
15
15
|
/.aws-sam
|
16
16
|
GITIGNORE
|