lamby-no-rails 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.python-version +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +17 -0
  6. data/Brewfile +5 -0
  7. data/CHANGELOG.md +109 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +3 -0
  10. data/Gemfile.lock +168 -0
  11. data/LICENSE.txt +21 -0
  12. data/Pipfile +13 -0
  13. data/Pipfile.lock +370 -0
  14. data/README.md +37 -0
  15. data/Rakefile +12 -0
  16. data/bin/bootstrap +20 -0
  17. data/bin/console +14 -0
  18. data/bin/setup +6 -0
  19. data/bin/test +5 -0
  20. data/bin/update +7 -0
  21. data/lamby.gemspec +29 -0
  22. data/lib/lamby.rb +25 -0
  23. data/lib/lamby/debug.rb +46 -0
  24. data/lib/lamby/handler.rb +71 -0
  25. data/lib/lamby/logger.rb +23 -0
  26. data/lib/lamby/rack.rb +85 -0
  27. data/lib/lamby/rack_alb.rb +73 -0
  28. data/lib/lamby/rack_api.rb +36 -0
  29. data/lib/lamby/railtie.rb +12 -0
  30. data/lib/lamby/sam_helpers.rb +9 -0
  31. data/lib/lamby/ssm_parameter_store.rb +154 -0
  32. data/lib/lamby/tasks.rake +15 -0
  33. data/lib/lamby/templates.rake +36 -0
  34. data/lib/lamby/templates/api_gateway.rb +25 -0
  35. data/lib/lamby/templates/api_gateway/app.rb +10 -0
  36. data/lib/lamby/templates/api_gateway/build +23 -0
  37. data/lib/lamby/templates/api_gateway/deploy +22 -0
  38. data/lib/lamby/templates/api_gateway/template.yaml +84 -0
  39. data/lib/lamby/templates/application_load_balancer.rb +25 -0
  40. data/lib/lamby/templates/application_load_balancer/app.rb +10 -0
  41. data/lib/lamby/templates/application_load_balancer/build +23 -0
  42. data/lib/lamby/templates/application_load_balancer/deploy +39 -0
  43. data/lib/lamby/templates/application_load_balancer/template.yaml +90 -0
  44. data/lib/lamby/templates/shared.rb +15 -0
  45. data/lib/lamby/version.rb +3 -0
  46. metadata +199 -0
@@ -0,0 +1,154 @@
1
+ require 'aws-sdk-ssm'
2
+
3
+ module Lamby
4
+ class SsmParameterStore
5
+
6
+ MAX_RESULTS = 10
7
+
8
+ Param = Struct.new :name, :env, :value
9
+
10
+ attr_reader :path, :params
11
+
12
+ class << self
13
+
14
+ def dotenv(path)
15
+ new(path).get!.to_dotenv
16
+ end
17
+
18
+ def get!(path)
19
+ parts = path.from(1).split('/')
20
+ env = parts.pop
21
+ path = "/#{parts.join('/')}"
22
+ new(path).get!.params.detect do |p|
23
+ p.env == env
24
+ end.try(:value)
25
+ end
26
+
27
+ end
28
+
29
+ def initialize(path, options = {})
30
+ @path = path
31
+ @params = []
32
+ @options = options
33
+ end
34
+
35
+ def to_env(overwrite: true)
36
+ params.each do |param|
37
+ overwrite ? ENV[param.env] = param.value : ENV[param.env] ||= param.value
38
+ end
39
+ end
40
+
41
+ def to_dotenv
42
+ File.open(dotenv_file, 'w') { |f| f.write(dotenv_contents) }
43
+ end
44
+
45
+ def get!
46
+ get_all!
47
+ get_history! if label.present?
48
+ self
49
+ end
50
+
51
+ def label
52
+ ENV['LAMBY_SSM_PARAMS_LABEL'] || @options[:label]
53
+ end
54
+
55
+ def client
56
+ @client ||= begin
57
+ options = @options[:client_options] || {}
58
+ Aws::SSM::Client.new(options)
59
+ end
60
+ end
61
+
62
+
63
+ private
64
+
65
+ def dotenv_file
66
+ @options[:dotenv_file] || ENV['LAMBY_SSM_PARAMS_FILE'] || Rails.root.join(".env.#{Rails.env}")
67
+ end
68
+
69
+ def dotenv_contents
70
+ params.each_with_object('') do |param, contents|
71
+ line = "export #{param.env}=#{param.value}\n"
72
+ contents << line
73
+ end
74
+ end
75
+
76
+ # Path
77
+
78
+ def get_all!
79
+ return params if @got_all
80
+ get_parse_all
81
+ while @all_response.next_token do get_parse_all end
82
+ @got_all = true
83
+ params
84
+ end
85
+
86
+ def get_parse_all
87
+ get_all
88
+ parse_all
89
+ end
90
+
91
+ def get_all
92
+ @all_response = client.get_parameters_by_path(get_all_options)
93
+ end
94
+
95
+ def get_all_options
96
+ { path: path,
97
+ recursive: true,
98
+ with_decryption: true,
99
+ max_results: MAX_RESULTS
100
+ }.tap { |options|
101
+ token = @all_response.try(:next_token)
102
+ options[:next_token] = token if token
103
+ }
104
+ end
105
+
106
+ def parse_all
107
+ @all_response.parameters.each do |p|
108
+ env = p.name.split('/').last
109
+ params << Param.new(p.name, env, p.value)
110
+ end
111
+ end
112
+
113
+ # History
114
+
115
+ def get_history!
116
+ return params if @got_history
117
+ params.each do |param|
118
+ name = param.name
119
+ get_parse_history(name)
120
+ while @hist_response.next_token do get_parse_history(name) end
121
+ end
122
+ @got_history = true
123
+ params
124
+ end
125
+
126
+ def get_parse_history(name)
127
+ get_history(name)
128
+ parse_history(name)
129
+ end
130
+
131
+ def get_history(name)
132
+ @hist_response = client.get_parameter_history(get_history_options(name))
133
+ end
134
+
135
+ def get_history_options(name)
136
+ { name: name,
137
+ with_decryption: true,
138
+ max_results: MAX_RESULTS
139
+ }.tap { |options|
140
+ token = @hist_response.try(:next_token)
141
+ options[:next_token] = token if token
142
+ }
143
+ end
144
+
145
+ def parse_history(name)
146
+ @hist_response.parameters.each do |p|
147
+ next unless p.labels.include? label
148
+ param = params.detect { |param| param.name == name }
149
+ param.value = p.value
150
+ end
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,15 @@
1
+ namespace :lamby do
2
+
3
+ namespace :ssm do
4
+
5
+ desc 'Create a Dotenv file.'
6
+ task :dotenv do
7
+ require 'lamby/ssm_parameter_store'
8
+ path = ENV['LAMBY_SSM_PARAMS_PATH']
9
+ raise ArgumentError, 'The LAMBY_SSM_PARAMS_PATH env is required.' unless path
10
+ Lamby::SsmParameterStore.dotenv(path)
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,36 @@
1
+ installers = {
2
+ 'API Gateway' => :api_gateway,
3
+ 'Application Load Balancer' => :application_load_balancer
4
+ }.freeze
5
+
6
+ namespace :lamby do
7
+ namespace :install do
8
+
9
+ installers.each do |name, task_name|
10
+ desc "Install Lamby files for #{name}"
11
+ task task_name do
12
+ exec "#{base_path} LOCATION=#{template(task_name)}"
13
+ end
14
+ end
15
+
16
+ def template(task_name)
17
+ File.expand_path "../lamby/templates/#{task_name}.rb", __dir__
18
+ end
19
+
20
+ def bin_path
21
+ ENV['BUNDLE_BIN'] || './bin'
22
+ end
23
+
24
+ def base_path
25
+ if Rails::VERSION::MAJOR >= 5
26
+ "#{RbConfig.ruby} #{bin_path}/rails app:template"
27
+ else
28
+ "#{RbConfig.ruby} #{bin_path}/rake rails:template"
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ desc "Install Lamby files for #{installers.first.first}"
35
+ task install: 'install:application_load_balancer'
36
+ end
@@ -0,0 +1,25 @@
1
+ $LAMBY_INSTALLER_NAME = 'api_gateway'
2
+ load 'lamby/templates/shared.rb'
3
+
4
+ say '==> Running Lamby API Gateway 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: :api
10
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Clean any previous bundle/builds.
5
+ rm -rf ./.aws-sam/build
6
+
7
+ # Ensure native extensions built for platform.
8
+ sam build --use-container
9
+
10
+ # [HOOK] Environments & Configuration
11
+ # https://lamby.custominktech.com/docs/environment_and_configuration
12
+
13
+ # [HOOK] Asset Hosts & Precompiling
14
+ # https://lamby.custominktech.com/docs/asset_host_and_precompiling
15
+
16
+ # Clean un-needed artifacts.
17
+ pushd ./.aws-sam/build/RailsFunction/
18
+ rm -rf .aws-sam \
19
+ .git \
20
+ log \
21
+ test \
22
+ tmp
23
+ popd
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ export RAILS_ENV=${RAILS_ENV:="production"}
5
+ export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:=us-east-1}
6
+ export CLOUDFORMATION_BUCKET=${CLOUDFORMATION_BUCKET:="lamby.cloudformation.$(whoami)"}
7
+
8
+ ./bin/build
9
+
10
+ sam package \
11
+ --region ${AWS_DEFAULT_REGION} \
12
+ --template-file ./.aws-sam/build/template.yaml \
13
+ --output-template-file ./.aws-sam/build/packaged.yaml \
14
+ --s3-bucket $CLOUDFORMATION_BUCKET \
15
+ --s3-prefix "APPNAMEHERE-${RAILS_ENV}"
16
+
17
+ sam deploy \
18
+ --template-file ./.aws-sam/build/packaged.yaml \
19
+ --stack-name "APPNAMEHERE-${RAILS_ENV}-${AWS_DEFAULT_REGION}" \
20
+ --capabilities "CAPABILITY_IAM" \
21
+ --parameter-overrides \
22
+ RailsEnv=${RAILS_ENV}
@@ -0,0 +1,84 @@
1
+ AWSTemplateFormatVersion: '2010-09-09'
2
+ Transform: AWS::Serverless-2016-10-31
3
+ Description: APPNAMEHERE Lambda (API)
4
+
5
+ Parameters:
6
+
7
+ RailsEnv:
8
+ Type: String
9
+ Default: production
10
+ AllowedValues:
11
+ - staging
12
+ - production
13
+
14
+ Resources:
15
+
16
+ RailsApi:
17
+ Type: AWS::Serverless::Api
18
+ Properties:
19
+ StageName: !Ref RailsEnv
20
+ EndpointConfiguration: REGIONAL
21
+ DefinitionBody:
22
+ swagger: 2.0
23
+ info: { title: !Ref 'AWS::StackName' }
24
+ basePath: !Join [ '', [ '/', !Ref RailsEnv ] ]
25
+ schemes: [ 'https' ]
26
+ paths:
27
+ /:
28
+ x-amazon-apigateway-any-method:
29
+ x-amazon-apigateway-integration:
30
+ uri:
31
+ Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RailsFunction.Arn}:live/invocations
32
+ httpMethod: POST
33
+ type: aws_proxy
34
+ /{resource+}:
35
+ x-amazon-apigateway-any-method:
36
+ parameters:
37
+ - name: resource
38
+ in: path
39
+ required: true
40
+ type: string
41
+ x-amazon-apigateway-integration:
42
+ uri:
43
+ Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RailsFunction.Arn}:live/invocations
44
+ httpMethod: POST
45
+ type: aws_proxy
46
+ x-amazon-apigateway-binary-media-types:
47
+ - '*/*'
48
+
49
+ RailsFunction:
50
+ Type: AWS::Serverless::Function
51
+ Properties:
52
+ CodeUri: .
53
+ Handler: app.handler
54
+ Runtime: ruby2.5
55
+ MemorySize: 512
56
+ Timeout: 30
57
+ Environment:
58
+ Variables:
59
+ RAILS_ENV: !Ref RailsEnv
60
+ FunctionName: !Join [ '', [ 'APPNAMEHERE-', !Ref RailsEnv, '-', !Ref 'AWS::Region' ] ]
61
+ Events:
62
+ Root:
63
+ Type: Api
64
+ Properties:
65
+ Path: /
66
+ Method: ANY
67
+ RestApiId: !Ref RailsApi
68
+ RailsAppAll:
69
+ Type: Api
70
+ Properties:
71
+ Path: /{resource+}
72
+ Method: ANY
73
+ RestApiId: !Ref RailsApi
74
+ AutoPublishAlias: live
75
+
76
+ Outputs:
77
+
78
+ RailsApiUrl:
79
+ Description: API Gateway Endpoint
80
+ Value: !Sub "https://${RailsApi}.execute-api.${AWS::Region}.amazonaws.com/${RailsEnv}/"
81
+
82
+ RailsFunctionArn:
83
+ Description: Lambda ARN
84
+ Value: !GetAtt RailsFunction.Arn
@@ -0,0 +1,25 @@
1
+ $LAMBY_INSTALLER_NAME = 'application_load_balancer'
2
+ load 'lamby/templates/shared.rb'
3
+
4
+ say '==> Running Lamby Application Load Balancer 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: :alb
10
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ # Clean any previous bundle/builds.
5
+ rm -rf ./.aws-sam/build
6
+
7
+ # Ensure native extensions built for platform.
8
+ sam build --use-container
9
+
10
+ # [HOOK] Environments & Configuration
11
+ # https://lamby.custominktech.com/docs/environment_and_configuration
12
+
13
+ # [HOOK] Asset Hosts & Precompiling
14
+ # https://lamby.custominktech.com/docs/asset_host_and_precompiling
15
+
16
+ # Clean un-needed artifacts.
17
+ pushd ./.aws-sam/build/RailsFunction/
18
+ rm -rf .aws-sam \
19
+ .git \
20
+ log \
21
+ test \
22
+ tmp
23
+ popd
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ export RAILS_ENV=${RAILS_ENV:="production"}
5
+ export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:=us-east-1}
6
+ export CLOUDFORMATION_BUCKET=${CLOUDFORMATION_BUCKET:="lamby.cloudformation.$(whoami)"}
7
+
8
+ ./bin/build
9
+
10
+ export VPCID=${VPCID:=$(
11
+ aws ec2 describe-vpcs \
12
+ --output text \
13
+ --filters 'Name=state,Values=available' \
14
+ --query 'Vpcs[0].VpcId'
15
+ )}
16
+
17
+ export SUBNETS=${SUBNETS:=$(
18
+ aws ec2 describe-subnets \
19
+ --output text \
20
+ --filters "Name=state,Values=available,Name=vpc-id,Values=$VPCID" \
21
+ --query 'Subnets[*].SubnetId' | \
22
+ tr -s '[:blank:]' ','
23
+ )}
24
+
25
+ sam package \
26
+ --region ${AWS_DEFAULT_REGION} \
27
+ --template-file ./.aws-sam/build/template.yaml \
28
+ --output-template-file ./.aws-sam/build/packaged.yaml \
29
+ --s3-bucket $CLOUDFORMATION_BUCKET \
30
+ --s3-prefix "APPNAMEHERE-${RAILS_ENV}"
31
+
32
+ sam deploy \
33
+ --template-file ./.aws-sam/build/packaged.yaml \
34
+ --stack-name "APPNAMEHERE-${RAILS_ENV}-${AWS_DEFAULT_REGION}" \
35
+ --capabilities "CAPABILITY_IAM" \
36
+ --parameter-overrides \
37
+ RailsEnv=${RAILS_ENV} \
38
+ VpcId=${VPCID} \
39
+ Subnets=${SUBNETS}