jets 0.5.8 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +2 -3
- data/jets.gemspec +1 -4
- data/lib/jets.rb +3 -2
- data/lib/jets/application.rb +18 -1
- data/lib/jets/aws_info.rb +36 -0
- data/lib/jets/aws_services.rb +5 -0
- data/lib/jets/builders/code_builder.rb +0 -1
- data/lib/jets/cfn/template_builders.rb +5 -2
- data/lib/jets/cfn/template_builders/api_gateway_builder.rb +2 -3
- data/lib/jets/cfn/template_builders/base_child_builder.rb +16 -0
- data/lib/jets/cfn/template_builders/function_properties/base_builder.rb +23 -1
- data/lib/jets/cfn/template_builders/iam_policy.rb +6 -0
- data/lib/jets/cfn/template_builders/iam_policy/application_policy.rb +18 -0
- data/lib/jets/cfn/template_builders/iam_policy/base_policy.rb +57 -0
- data/lib/jets/cfn/template_builders/iam_policy/class_policy.rb +20 -0
- data/lib/jets/cfn/template_builders/iam_policy/function_policy.rb +21 -0
- data/lib/jets/cfn/template_builders/interface.rb +1 -1
- data/lib/jets/cfn/template_builders/parent_builder.rb +4 -6
- data/lib/jets/cfn/template_builders/templates/minimal-stack.yml +0 -36
- data/lib/jets/cfn/template_mappers.rb +2 -0
- data/lib/jets/cfn/template_mappers/iam_policy.rb +6 -0
- data/lib/jets/cfn/template_mappers/iam_policy/application_policy_mapper.rb +28 -0
- data/lib/jets/cfn/template_mappers/iam_policy/base_policy_mapper.rb +44 -0
- data/lib/jets/cfn/template_mappers/iam_policy/class_policy_mapper.rb +32 -0
- data/lib/jets/cfn/template_mappers/iam_policy/function_policy_mapper.rb +32 -0
- data/lib/jets/cfn/template_mappers/lambda_function_mapper.rb +3 -1
- data/lib/jets/commands/build.rb +2 -2
- data/lib/jets/commands/call.rb +1 -1
- data/lib/jets/core.rb +5 -1
- data/lib/jets/internal/app/controllers/jets/public_controller.rb +1 -2
- data/lib/jets/internal/app/jobs/jets/preheat_job.rb +14 -0
- data/lib/jets/lambda/dsl.rb +20 -1
- data/lib/jets/lambda/task.rb +2 -1
- data/lib/jets/version.rb +1 -1
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b156a3904d427d2d2604ad4026e069c6efe7a724c6c3937c9bd0a8cc28ecdda2
|
4
|
+
data.tar.gz: 4fb811e051ea4cf10dd5032a2b127a0b92b686d3e9818640fe8e10f2cc6b34a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c137bfe10a6a4c07af49d524a95374ca26c124b5367054015e709adaa200c748b2187b4275e69495cff5a0cef60c70e52e6abb8be81bd0a524953c96d7043b6a
|
7
|
+
data.tar.gz: e823f819bc813e3e78b99ca76c38aae10ee644178b73ad4728bc5bdea70818bfc544af116020e89c472d2cd5ac99fee79244e69fea2aacb26644a37e3fae9888
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
|
5
5
|
|
6
|
+
## [0.6.0]
|
7
|
+
- fine grain iam policy abilities: pull request #13 from tongueroo/iam-policy
|
8
|
+
- changed quite a few logical ids in the CloudFormation templates
|
9
|
+
|
6
10
|
## [0.5.8]
|
7
11
|
- fix config.prewarm defaults
|
8
12
|
|
data/Gemfile
CHANGED
@@ -4,9 +4,8 @@ source "https://rubygems.org"
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
# required here for specs
|
7
|
-
# TODO:
|
8
|
-
#
|
9
|
-
# jets/webpacker/middleware_setup.rb
|
7
|
+
# TODO: Only require webpacker in Gemfile of project if possible.
|
8
|
+
# Need both because of jets/application.rb and jets/webpacker/middleware_setup.rb
|
10
9
|
group :development, :test do
|
11
10
|
gem "webpacker", git: "https://github.com/tongueroo/webpacker.git", branch: "jets"
|
12
11
|
gem "rspec_junit_formatter"
|
data/jets.gemspec
CHANGED
@@ -31,8 +31,6 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_dependency "actionpack"
|
32
32
|
spec.add_dependency "activerecord"
|
33
33
|
spec.add_dependency "railties" # ActiveRecord database_tasks.rb require this
|
34
|
-
# TODO: only load the database adapters that the app uses, so generate this
|
35
|
-
# in the app's Gemfile
|
36
34
|
spec.add_dependency "dotenv"
|
37
35
|
|
38
36
|
spec.add_dependency "recursive-open-struct"
|
@@ -45,8 +43,7 @@ Gem::Specification.new do |spec|
|
|
45
43
|
spec.add_dependency "text-table"
|
46
44
|
spec.add_dependency "rack"
|
47
45
|
spec.add_dependency "json"
|
48
|
-
#
|
49
|
-
# in the app. but we want to have them so we can run specs.
|
46
|
+
# TODO: only load the database adapters that app's Gemfile instead of jets.gemspec
|
50
47
|
spec.add_dependency "pg", "=0.21"
|
51
48
|
|
52
49
|
spec.add_dependency "gems" # lambdagem dependency
|
data/lib/jets.rb
CHANGED
@@ -5,7 +5,7 @@ require "active_support/core_ext/string"
|
|
5
5
|
require "active_support/ordered_hash"
|
6
6
|
require "colorize"
|
7
7
|
require "fileutils"
|
8
|
-
require "pp" # TODO:
|
8
|
+
require "pp" # TODO: Remove pp after debugging
|
9
9
|
require "memoist"
|
10
10
|
|
11
11
|
module Jets
|
@@ -15,6 +15,7 @@ module Jets
|
|
15
15
|
autoload :CLI, "jets/cli"
|
16
16
|
autoload :Commands, "jets/commands"
|
17
17
|
|
18
|
+
autoload :AwsInfo, "jets/aws_info"
|
18
19
|
autoload :AwsServices, "jets/aws_services"
|
19
20
|
autoload :Builders, 'jets/builders'
|
20
21
|
autoload :Call, "jets/call"
|
@@ -57,7 +58,7 @@ if File.exist?("#{Jets.root}config/dynamodb.yml")
|
|
57
58
|
require "dynomite"
|
58
59
|
end
|
59
60
|
|
60
|
-
# https://makandracards.com/makandra/42521-detecting-if-a-ruby-gem-is-loaded
|
61
|
+
# Thanks: https://makandracards.com/makandra/42521-detecting-if-a-ruby-gem-is-loaded
|
61
62
|
# TODO: move require "pg" into loader class and abstract to support more gems
|
62
63
|
if File.exist?("#{Jets.root}config/database.yml")
|
63
64
|
require "active_record"
|
data/lib/jets/application.rb
CHANGED
@@ -82,9 +82,21 @@ class Jets::Application
|
|
82
82
|
# IE: With env_extra: project-dev-1
|
83
83
|
# Without env_extra: project-dev
|
84
84
|
config.short_env = ENV_MAP[Jets.env.to_sym] || Jets.env
|
85
|
-
config.project_namespace = [config.project_name, config.short_env, config.env_extra].compact.join('-')
|
86
85
|
# table_namespace does not have the env_extra, more common case desired.
|
87
86
|
config.table_namespace = [config.project_name, config.short_env].compact.join('-')
|
87
|
+
|
88
|
+
project_namespace = [config.project_name, config.short_env, config.env_extra].compact.join('-')
|
89
|
+
config.project_namespace = project_namespace
|
90
|
+
|
91
|
+
# config.iam_policy = ["logs2:*"]
|
92
|
+
# Must set defaul t iam_policy here instead of `def config` because we need access to
|
93
|
+
# the project_namespace and if we call it from `def config` we get an infinit loop
|
94
|
+
config.iam_policy = [{
|
95
|
+
sid: "Statement1",
|
96
|
+
action: ["logs:*"],
|
97
|
+
effect: "Allow",
|
98
|
+
resource: "arn:aws:logs:#{Jets.aws.region}:#{Jets.aws.account}:log-group:#{project_namespace}-*",
|
99
|
+
}]
|
88
100
|
end
|
89
101
|
|
90
102
|
# It is pretty easy to attempt to set environment variables without
|
@@ -124,4 +136,9 @@ class Jets::Application
|
|
124
136
|
require routes_file if File.exist?(routes_file)
|
125
137
|
end
|
126
138
|
|
139
|
+
def aws
|
140
|
+
Jets::AwsInfo.new
|
141
|
+
end
|
142
|
+
memoize :aws
|
143
|
+
|
127
144
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module Jets
|
3
|
+
class AwsInfo
|
4
|
+
extend Memoist
|
5
|
+
include AwsServices
|
6
|
+
|
7
|
+
def region
|
8
|
+
return 'us-east-1' if ENV['TEST']
|
9
|
+
|
10
|
+
region = nil
|
11
|
+
|
12
|
+
# First try to get it from the ~/.aws/config
|
13
|
+
region = `aws configure get region`.strip rescue nil
|
14
|
+
return region if region
|
15
|
+
|
16
|
+
# Second try the metadata endpoint, should be available on AWS Lambda environment
|
17
|
+
# https://stackoverflow.com/questions/4249488/find-region-from-within-an-ec2-instance
|
18
|
+
begin
|
19
|
+
az = `curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`
|
20
|
+
region = az.strip.chop # remove last char
|
21
|
+
rescue
|
22
|
+
end
|
23
|
+
return region if region
|
24
|
+
|
25
|
+
ENV['JETS_AWS_REGION'] || 'us-east-1' # default if all else fails
|
26
|
+
end
|
27
|
+
memoize :region
|
28
|
+
|
29
|
+
# aws sts get-caller-identity
|
30
|
+
def account
|
31
|
+
return '123456789' if ENV['TEST']
|
32
|
+
sts.get_caller_identity.account
|
33
|
+
end
|
34
|
+
memoize :account
|
35
|
+
end
|
36
|
+
end
|
data/lib/jets/aws_services.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "aws-sdk-s3"
|
2
2
|
require "aws-sdk-cloudformation"
|
3
3
|
require "aws-sdk-lambda"
|
4
|
+
require "aws-sdk-sts"
|
4
5
|
|
5
6
|
module Jets::AwsServices
|
6
7
|
def s3
|
@@ -19,6 +20,10 @@ module Jets::AwsServices
|
|
19
20
|
@lambda ||= Aws::Lambda::Client.new
|
20
21
|
end
|
21
22
|
|
23
|
+
def sts
|
24
|
+
@sts ||= Aws::STS::Client.new
|
25
|
+
end
|
26
|
+
|
22
27
|
def stack_exists?(stack_name)
|
23
28
|
return false if ENV['TEST']
|
24
29
|
|
@@ -359,7 +359,6 @@ EOL
|
|
359
359
|
md = spec.source.to_s.match(/@(\w+)\)/)
|
360
360
|
git_sha = md[1]
|
361
361
|
end
|
362
|
-
puts "git_shas #{git_shas.inspect}"
|
363
362
|
|
364
363
|
# IE: /tmp/jets/demo/cache/bundled/gems/ruby/2.5.0/bundler/gems/webpacker-a8c46614c675
|
365
364
|
Dir.glob("#{cache_area}/bundled/gems/ruby/2.5.0/bundler/gems/*").each do |path|
|
@@ -2,6 +2,7 @@ require 'active_support/core_ext/hash'
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
class Jets::Cfn
|
5
|
+
# TODO: Refactor builder classes. They all work slightly differently.
|
5
6
|
class TemplateBuilders
|
6
7
|
autoload :Interface, "jets/cfn/template_builders/interface"
|
7
8
|
autoload :ParentBuilder, "jets/cfn/template_builders/parent_builder"
|
@@ -15,7 +16,9 @@ class Jets::Cfn
|
|
15
16
|
|
16
17
|
autoload :ApiGatewayBuilder, "jets/cfn/template_builders/api_gateway_builder"
|
17
18
|
autoload :ApiGatewayDeploymentBuilder, "jets/cfn/template_builders/api_gateway_deployment_builder"
|
18
|
-
|
19
|
-
|
19
|
+
|
20
|
+
# separate beasts:
|
21
|
+
autoload :FunctionProperties, "jets/cfn/template_builders/function_properties" # sort of a builder
|
22
|
+
autoload :IamPolicy, "jets/cfn/template_builders/iam_policy" # resource only
|
20
23
|
end
|
21
24
|
end
|
@@ -43,9 +43,8 @@ class Jets::Cfn::TemplateBuilders
|
|
43
43
|
# Adds route related Resources and Outputs
|
44
44
|
def add_gateway_routes
|
45
45
|
# The routes required a Gateway Resource to contain them.
|
46
|
-
# TODO: outputing all routes in 1 template will hit the 60 routes limit
|
47
|
-
# Will have to either output them as a joined string or
|
48
|
-
# break this up to multiple tempaltes.
|
46
|
+
# TODO: Support more routes. Right now outputing all routes in 1 template will hit the 60 routes limit.
|
47
|
+
# Will have to either output them as a joined string or break this up to multiple tempaltes.
|
49
48
|
# http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html
|
50
49
|
# Outputs: Maximum number of outputs that you can declare in your AWS CloudFormation template. 60 outputs
|
51
50
|
# Output name: Maximum size of an output name. 255 characters.
|
@@ -20,8 +20,10 @@ class Jets::Cfn::TemplateBuilders
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def add_functions
|
23
|
+
add_class_iam_policy if @app_klass.class_iam_policy
|
23
24
|
@app_klass.tasks.each do |task|
|
24
25
|
add_function(task)
|
26
|
+
add_iam_policy(task) if task.iam_policy
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
@@ -34,5 +36,19 @@ class Jets::Cfn::TemplateBuilders
|
|
34
36
|
logical_id = builder.map.logical_id
|
35
37
|
add_resource(logical_id, "AWS::Lambda::Function", builder.properties)
|
36
38
|
end
|
39
|
+
|
40
|
+
def add_class_iam_policy
|
41
|
+
map = Jets::Cfn::TemplateMappers::IamPolicy::ClassPolicyMapper.new(@app_klass)
|
42
|
+
logical_id = map.logical_id
|
43
|
+
properties = map.properties
|
44
|
+
add_resource(logical_id, "AWS::IAM::Role", properties)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_iam_policy(task)
|
48
|
+
map = Jets::Cfn::TemplateMappers::IamPolicy::FunctionPolicyMapper.new(task)
|
49
|
+
logical_id = map.logical_id
|
50
|
+
properties = map.properties
|
51
|
+
add_resource(logical_id, "AWS::IAM::Role", properties)
|
52
|
+
end
|
37
53
|
end
|
38
54
|
end
|
@@ -79,10 +79,19 @@ module Jets::Cfn::TemplateBuilders::FunctionProperties
|
|
79
79
|
# class_timeout 22
|
80
80
|
# ...
|
81
81
|
# end
|
82
|
+
#
|
83
|
+
# Also handles iam policy override at the class level. Example:
|
84
|
+
#
|
85
|
+
# class_iam_policy("logs:*")
|
86
|
+
#
|
82
87
|
def class_properties
|
83
88
|
# klass is PostsController, HardJob, GameRule, Hello or HelloFunction
|
84
89
|
klass = Jets::Klass.from_task(@task)
|
85
90
|
class_properties = klass.class_properties
|
91
|
+
if klass.class_iam_policy
|
92
|
+
map = Jets::Cfn::TemplateMappers::IamPolicy::ClassPolicyMapper.new(klass)
|
93
|
+
class_properties[:Role] = "!GetAtt #{map.logical_id}.Arn"
|
94
|
+
end
|
86
95
|
Pascalize.pascalize(class_properties.deep_stringify_keys)
|
87
96
|
end
|
88
97
|
|
@@ -93,8 +102,21 @@ module Jets::Cfn::TemplateBuilders::FunctionProperties
|
|
93
102
|
# def index
|
94
103
|
# ...
|
95
104
|
# end
|
105
|
+
#
|
106
|
+
# Also handles iam policy override at the function level. Example:
|
107
|
+
#
|
108
|
+
# iam_policy("ec2:*")
|
109
|
+
# def new
|
110
|
+
# render json: params.merge(action: "new")
|
111
|
+
# end
|
112
|
+
#
|
96
113
|
def function_properties
|
97
|
-
|
114
|
+
properties = @task.properties
|
115
|
+
if @task.iam_policy
|
116
|
+
map = Jets::Cfn::TemplateMappers::IamPolicy::FunctionPolicyMapper.new(@task)
|
117
|
+
properties[:Role] = "!GetAtt #{map.logical_id}.Arn"
|
118
|
+
end
|
119
|
+
Pascalize.pascalize(properties.deep_stringify_keys)
|
98
120
|
end
|
99
121
|
|
100
122
|
def env_file_properties
|
@@ -0,0 +1,6 @@
|
|
1
|
+
module Jets::Cfn::TemplateBuilders::IamPolicy
|
2
|
+
autoload :ApplicationPolicy, "jets/cfn/template_builders/iam_policy/application_policy"
|
3
|
+
autoload :BasePolicy, "jets/cfn/template_builders/iam_policy/base_policy"
|
4
|
+
autoload :ClassPolicy, "jets/cfn/template_builders/iam_policy/class_policy"
|
5
|
+
autoload :FunctionPolicy, "jets/cfn/template_builders/iam_policy/function_policy"
|
6
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Implements:
|
2
|
+
# initialize
|
3
|
+
# policy_name
|
4
|
+
#
|
5
|
+
module Jets::Cfn::TemplateBuilders::IamPolicy
|
6
|
+
class ApplicationPolicy < BasePolicy
|
7
|
+
def initialize
|
8
|
+
setup
|
9
|
+
@definitions = Jets.config.iam_policy || [] # config.iam_policy contains definitions
|
10
|
+
end
|
11
|
+
|
12
|
+
# Example: PostsControllerPolicy or SleepJobPolicy
|
13
|
+
# Note: There is no "method" in the name
|
14
|
+
def policy_name
|
15
|
+
"ApplicationPolicy"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Classes that inherit this Base class should implement:
|
2
|
+
#
|
3
|
+
# initialize - should call setup in it
|
4
|
+
# policy_name
|
5
|
+
#
|
6
|
+
module Jets::Cfn::TemplateBuilders::IamPolicy
|
7
|
+
class BasePolicy
|
8
|
+
extend Memoist
|
9
|
+
|
10
|
+
attr_reader :definitions
|
11
|
+
# Not using initialize because method signature is different
|
12
|
+
def setup
|
13
|
+
# empty starting policy that will be changed
|
14
|
+
@policy = {
|
15
|
+
"Version" => "2012-10-17",
|
16
|
+
"Statement" => []
|
17
|
+
}
|
18
|
+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_sid.html
|
19
|
+
@sid = 0 # counter
|
20
|
+
end
|
21
|
+
|
22
|
+
def policy_document
|
23
|
+
definitions.map { |definition| standardize(definition) }
|
24
|
+
# Thanks: https://www.mnishiguchi.com/2017/11/29/rails-hash-camelize-and-underscore-keys/
|
25
|
+
@policy.deep_transform_keys! { |key| key.to_s.camelize }
|
26
|
+
end
|
27
|
+
memoize :policy_document # only process policy_document once
|
28
|
+
|
29
|
+
def standardize(definition)
|
30
|
+
@sid += 1
|
31
|
+
case definition
|
32
|
+
when String
|
33
|
+
@policy["Statement"] << {
|
34
|
+
sid: "Stmt#{@sid}",
|
35
|
+
action: [definition],
|
36
|
+
effect: "Allow",
|
37
|
+
resource: "*",
|
38
|
+
}
|
39
|
+
when Hash
|
40
|
+
definition = definition.stringify_keys
|
41
|
+
if definition.key?("Version") # special case where we replace the policy entirely
|
42
|
+
@policy = definition
|
43
|
+
else
|
44
|
+
@policy["Statement"] << definition
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Need to underscore and then classify again for this case:
|
50
|
+
# Jets::PreheatJob_policy => JetsPreheatJobPolicy
|
51
|
+
# Or else you we get this:
|
52
|
+
# Jets::PreheatJob_policy => JetsPreheatjobPolicy
|
53
|
+
def classify_name(text)
|
54
|
+
text.gsub('::','_').underscore.classify
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Implements:
|
2
|
+
# initialize
|
3
|
+
# policy_name
|
4
|
+
#
|
5
|
+
module Jets::Cfn::TemplateBuilders::IamPolicy
|
6
|
+
class ClassPolicy < BasePolicy
|
7
|
+
def initialize(app_class)
|
8
|
+
setup
|
9
|
+
@app_class = app_class
|
10
|
+
# IE: @app_class: PostsController, HardJob, Hello, HelloFunction
|
11
|
+
@definitions = app_class.class_iam_policy || [] # class_iam_policy contains definitions
|
12
|
+
end
|
13
|
+
|
14
|
+
# Example: PostsControllerPolicy or SleepJobPolicy
|
15
|
+
# Note: There is no "method" in the name
|
16
|
+
def policy_name
|
17
|
+
classify_name("#{@app_class}_policy")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Implements:
|
2
|
+
# initialize
|
3
|
+
# policy_name
|
4
|
+
#
|
5
|
+
module Jets::Cfn::TemplateBuilders::IamPolicy
|
6
|
+
class FunctionPolicy < BasePolicy
|
7
|
+
def initialize(task)
|
8
|
+
setup
|
9
|
+
@task = task
|
10
|
+
@app_class = task.class_name.to_s
|
11
|
+
# IE: @app_class: PostsController, HardJob, Hello, HelloFunction
|
12
|
+
|
13
|
+
@definitions = task.iam_policy || [] # iam_policy contains definitions
|
14
|
+
end
|
15
|
+
|
16
|
+
# Example: PostsControllerIndexPolicy or SleepJobPerformPolicy
|
17
|
+
def policy_name
|
18
|
+
classify_name("#{@app_class}_#{@task.meth}_policy")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -43,7 +43,7 @@ class Jets::Cfn::TemplateBuilders
|
|
43
43
|
results.join("\n") + "\n"
|
44
44
|
end
|
45
45
|
|
46
|
-
# add_resource handles an options Hash with both only
|
46
|
+
# add_resource handles an options Hash with both only Properties
|
47
47
|
# and also one with a nested Properties.
|
48
48
|
|
49
49
|
# Example:
|
@@ -32,9 +32,11 @@ class Jets::Cfn::TemplateBuilders
|
|
32
32
|
}
|
33
33
|
rendered_result = Jets::Erb.result(path, variables)
|
34
34
|
minimal_template = YAML.load(rendered_result)
|
35
|
-
|
36
|
-
# minimal_template = YAML.load(IO.read(path))
|
37
35
|
@template.deep_merge!(minimal_template)
|
36
|
+
|
37
|
+
# Add application-wide IAM policy from Jets.config.iam_role
|
38
|
+
map = Jets::Cfn::TemplateMappers::IamPolicy::ApplicationPolicyMapper.new
|
39
|
+
add_resource(map.logical_id, "AWS::IAM::Role", map.properties)
|
38
40
|
end
|
39
41
|
|
40
42
|
def add_child_resources
|
@@ -48,7 +50,6 @@ class Jets::Cfn::TemplateBuilders
|
|
48
50
|
#
|
49
51
|
# map = Jets::Cfn::TemplateMappers::ControllerMapper.new(path, s3_bucket)
|
50
52
|
# map = Jets::Cfn::TemplateMappers::JobMapper.new(path, s3_bucket)
|
51
|
-
# map = Jets::Cfn::TemplateMappers::FunctionMapper.new(path, s3_bucket)
|
52
53
|
#
|
53
54
|
mapper_class_name = File.basename(path, '.yml').split('_').last
|
54
55
|
mapper_class_name = mapper_class_name.classify
|
@@ -68,9 +69,6 @@ class Jets::Cfn::TemplateBuilders
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
|
-
# Each shared stacks has different logic.
|
72
|
-
# Handle in ugly case statement until we see the common patterns between them.
|
73
|
-
# TODO: clean up the add_shared_stack logical after we figure out the common interface pattern
|
74
72
|
def add_api_gateway
|
75
73
|
path = "#{Jets.config.project_namespace}-api-gateway.yml"
|
76
74
|
map = Jets::Cfn::TemplateMappers::ApiGatewayMapper.new(path, @options[:s3_bucket])
|
@@ -2,42 +2,6 @@
|
|
2
2
|
Resources:
|
3
3
|
S3Bucket:
|
4
4
|
Type: AWS::S3::Bucket
|
5
|
-
IamRole:
|
6
|
-
Type: AWS::IAM::Role
|
7
|
-
Properties:
|
8
|
-
AssumeRolePolicyDocument:
|
9
|
-
Version: '2012-10-17'
|
10
|
-
Statement:
|
11
|
-
- Effect: Allow
|
12
|
-
Principal:
|
13
|
-
Service:
|
14
|
-
- lambda.amazonaws.com
|
15
|
-
Action:
|
16
|
-
- sts:AssumeRole
|
17
|
-
Policies:
|
18
|
-
- PolicyName: <%= @policy_name %>
|
19
|
-
PolicyDocument:
|
20
|
-
Version: '2012-10-17'
|
21
|
-
Statement:
|
22
|
-
- Effect: Allow
|
23
|
-
Action:
|
24
|
-
- logs:*
|
25
|
-
Resource: '*'
|
26
|
-
# TODO: Make IAM permissions more fine grain for mimimal stack
|
27
|
-
# - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/quiz-dev-hello:*:*
|
28
|
-
# - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/quiz-dev-quiz:*:*
|
29
|
-
# TODO: Allow hook so user can configure IAM themselves and support managed polices
|
30
|
-
- Effect: Allow
|
31
|
-
Action:
|
32
|
-
- dynamodb:*
|
33
|
-
Resource: "*"
|
34
|
-
# required for PreheatJob which calls the other lambda functions repeatedly
|
35
|
-
- Effect: Allow
|
36
|
-
Action:
|
37
|
-
- lambda:*
|
38
|
-
Resource: "*"
|
39
|
-
Path: "/"
|
40
|
-
RoleName: <%= @role_name %>
|
41
5
|
Outputs:
|
42
6
|
S3Bucket:
|
43
7
|
Value: "!Ref S3Bucket" # not a valid cfn notation, surrounding double quotes is handled by post processing.
|
@@ -0,0 +1,6 @@
|
|
1
|
+
module Jets::Cfn::TemplateMappers::IamPolicy
|
2
|
+
autoload :ApplicationPolicyMapper, "jets/cfn/template_mappers/iam_policy/application_policy_mapper"
|
3
|
+
autoload :BasePolicyMapper, "jets/cfn/template_mappers/iam_policy/base_policy_mapper"
|
4
|
+
autoload :ClassPolicyMapper, "jets/cfn/template_mappers/iam_policy/class_policy_mapper"
|
5
|
+
autoload :FunctionPolicyMapper, "jets/cfn/template_mappers/iam_policy/function_policy_mapper"
|
6
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Implements:
|
2
|
+
#
|
3
|
+
# initialize
|
4
|
+
# iam_policy
|
5
|
+
# logical_id
|
6
|
+
# role_name
|
7
|
+
#
|
8
|
+
module Jets::Cfn::TemplateMappers::IamPolicy
|
9
|
+
class ApplicationPolicyMapper < BasePolicyMapper
|
10
|
+
def initialize; end # does nothing
|
11
|
+
|
12
|
+
def iam_policy
|
13
|
+
Jets::Cfn::TemplateBuilders::IamPolicy::ApplicationPolicy.new
|
14
|
+
end
|
15
|
+
memoize :iam_policy
|
16
|
+
|
17
|
+
# Example: PostsControllerLambdaFunction
|
18
|
+
# Note there are is no "Show" action in the name
|
19
|
+
def logical_id
|
20
|
+
"IamRole" # very simple logical ideal for the application-wide logical id
|
21
|
+
end
|
22
|
+
|
23
|
+
# There should be namespace in the role_name.
|
24
|
+
def role_name
|
25
|
+
"#{namespace}_application_iam_role".underscore.dasherize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Class that inherits this base class should implement:
|
2
|
+
#
|
3
|
+
# initialize
|
4
|
+
# iam_policy
|
5
|
+
# logical_id
|
6
|
+
# role_name
|
7
|
+
#
|
8
|
+
module Jets::Cfn::TemplateMappers::IamPolicy
|
9
|
+
class BasePolicyMapper
|
10
|
+
extend Memoist
|
11
|
+
|
12
|
+
def properties
|
13
|
+
properties = {
|
14
|
+
AssumeRolePolicyDocument: {
|
15
|
+
Version: "2012-10-17",
|
16
|
+
Statement: [{
|
17
|
+
Effect: "Allow",
|
18
|
+
Principal: {Service: ["lambda.amazonaws.com"]},
|
19
|
+
Action: ["sts:AssumeRole"]}
|
20
|
+
]},
|
21
|
+
Path: "/"
|
22
|
+
}
|
23
|
+
properties[:Policies] = [
|
24
|
+
PolicyName: iam_policy.policy_name,
|
25
|
+
PolicyDocument: iam_policy.policy_document,
|
26
|
+
]
|
27
|
+
properties[:RoleName] = role_name
|
28
|
+
properties.deep_stringify_keys!
|
29
|
+
properties
|
30
|
+
end
|
31
|
+
|
32
|
+
def namespace
|
33
|
+
Jets.config.project_namespace.underscore
|
34
|
+
end
|
35
|
+
|
36
|
+
# Need to underscore and then classify again for this case:
|
37
|
+
# Jets::PreheatJob_policy => JetsPreheatJobPolicy
|
38
|
+
# Or else you we get this:
|
39
|
+
# Jets::PreheatJob_policy => JetsPreheatjobPolicy
|
40
|
+
def classify_name(text)
|
41
|
+
text.gsub('::','_').underscore.classify
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Implements:
|
2
|
+
#
|
3
|
+
# initialize
|
4
|
+
# iam_policy
|
5
|
+
# logical_id
|
6
|
+
# role_name
|
7
|
+
#
|
8
|
+
module Jets::Cfn::TemplateMappers::IamPolicy
|
9
|
+
class ClassPolicyMapper < BasePolicyMapper
|
10
|
+
def initialize(app_class)
|
11
|
+
@app_class = app_class
|
12
|
+
# IE: @app_class: PostsController, HardJob, Hello, HelloFunction
|
13
|
+
end
|
14
|
+
|
15
|
+
def iam_policy
|
16
|
+
Jets::Cfn::TemplateBuilders::IamPolicy::ClassPolicy.new(@app_class)
|
17
|
+
end
|
18
|
+
memoize :iam_policy
|
19
|
+
|
20
|
+
# Example: PostsControllerLambdaFunction
|
21
|
+
# Note there are is no "Show" action in the name
|
22
|
+
# There should be no namespace in the logical_id.
|
23
|
+
def logical_id
|
24
|
+
classify_name("#{@app_class}_iam_role")
|
25
|
+
end
|
26
|
+
|
27
|
+
# There should be namespace in the role_name.
|
28
|
+
def role_name
|
29
|
+
classify_name("#{namespace}_#{@app_class}_iam_role").underscore.dasherize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Implements:
|
2
|
+
#
|
3
|
+
# initialize
|
4
|
+
# iam_policy
|
5
|
+
# logical_id
|
6
|
+
# role_name
|
7
|
+
#
|
8
|
+
module Jets::Cfn::TemplateMappers::IamPolicy
|
9
|
+
class FunctionPolicyMapper < BasePolicyMapper
|
10
|
+
def initialize(task)
|
11
|
+
@task = task
|
12
|
+
@app_class = task.class_name.to_s
|
13
|
+
# IE: @app_class: PostsController, HardJob, Hello, HelloFunction
|
14
|
+
end
|
15
|
+
|
16
|
+
def iam_policy
|
17
|
+
Jets::Cfn::TemplateBuilders::IamPolicy::FunctionPolicy.new(@task)
|
18
|
+
end
|
19
|
+
memoize :iam_policy
|
20
|
+
|
21
|
+
# Example: PostsControllerShowLambdaFunction
|
22
|
+
# There should be no namespace in the logical_id.
|
23
|
+
def logical_id
|
24
|
+
classify_name("#{@app_class}_#{@task.meth}_iam_role")
|
25
|
+
end
|
26
|
+
|
27
|
+
# There should be namespace in the role_name.
|
28
|
+
def role_name
|
29
|
+
classify_name("#{namespace}_#{@app_class}_#{@task.meth}_iam_role").underscore.dasherize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -13,7 +13,9 @@ class Jets::Cfn::TemplateMappers
|
|
13
13
|
|
14
14
|
def environment
|
15
15
|
env = Jets.config.environment ? Jets.config.environment.to_h : {}
|
16
|
-
|
16
|
+
jets_env_options = {JETS_ENV: Jets.env.to_s}
|
17
|
+
jets_env_options[:JETS_ENV_EXTRA] = Jets.config.env_extra if Jets.config.env_extra
|
18
|
+
env.deep_merge(jets_env_options)
|
17
19
|
end
|
18
20
|
|
19
21
|
# Example: PostsControllerIndex or SleepJobPerform
|
data/lib/jets/commands/build.rb
CHANGED
@@ -41,7 +41,7 @@ module Jets::Commands
|
|
41
41
|
|
42
42
|
def build_all_templates
|
43
43
|
clean_templates
|
44
|
-
# TODO: move this
|
44
|
+
# TODO: Maybe move this tbuild.rb template related logic to cfn/builder.rb
|
45
45
|
## CloudFormation templates
|
46
46
|
puts "Building Lambda functions as CloudFormation templates."
|
47
47
|
# 1. Shared templates - child templates needs them
|
@@ -107,7 +107,7 @@ module Jets::Commands
|
|
107
107
|
# Crucial that the Dir.pwd is in the tmp_app_root because for
|
108
108
|
# because Jets.boot set ups autoload_paths and this is how project
|
109
109
|
# classes are loaded.
|
110
|
-
# TODO: rework code so
|
110
|
+
# TODO: rework code so that Dir.pwd does not have to be in tmp_app_root for build to work.
|
111
111
|
def self.app_files
|
112
112
|
paths = []
|
113
113
|
expression = "#{Jets.root}app/**/**/*.rb"
|
data/lib/jets/commands/call.rb
CHANGED
@@ -146,9 +146,9 @@ class Jets::Commands::Call
|
|
146
146
|
puts "Pro tip: The Lambda Console Link to the #{function_name} function has been added to your clipboard." unless @options[:mute]
|
147
147
|
end
|
148
148
|
|
149
|
+
# TODO: Hook client_context up and maek sure it works. Think I've figure out how to sign client_context below.
|
149
150
|
# Client context must be a valid Base64-encoded JSON object
|
150
151
|
# Example: http://docs.aws.amazon.com/mobileanalytics/latest/ug/PutEvents.html
|
151
|
-
# TODO: figure out how to sign client_context
|
152
152
|
def client_context
|
153
153
|
context = {
|
154
154
|
"client" => {
|
data/lib/jets/core.rb
CHANGED
@@ -23,6 +23,10 @@ module Jets::Core
|
|
23
23
|
application.config
|
24
24
|
end
|
25
25
|
|
26
|
+
def aws
|
27
|
+
application.aws
|
28
|
+
end
|
29
|
+
|
26
30
|
# Load all application base classes and project classes
|
27
31
|
def boot
|
28
32
|
Jets::Booter.boot!
|
@@ -77,7 +81,7 @@ module Jets::Core
|
|
77
81
|
def version
|
78
82
|
Jets::VERSION
|
79
83
|
end
|
80
|
-
|
84
|
+
|
81
85
|
def eager_load!
|
82
86
|
Dir.glob("#{Jets.root}app/**/*.rb").select do |path|
|
83
87
|
next if !File.file?(path) or path =~ %r{/javascript/} or path =~ %r{/views/}
|
@@ -2,8 +2,7 @@ require "rack/mime"
|
|
2
2
|
|
3
3
|
# Works for utf8 text files.
|
4
4
|
# TODO: Add support to public_controller for binary data like images.
|
5
|
-
# Tricky because API Gateway is not respecting the Accept header
|
6
|
-
# same way as browsers.
|
5
|
+
# Tricky because API Gateway is not respecting the Accept header the same way as browsers.
|
7
6
|
class Jets::PublicController < Jets::Controller::Base
|
8
7
|
layout false
|
9
8
|
internal true
|
@@ -7,6 +7,20 @@ class Jets::PreheatJob < ApplicationJob
|
|
7
7
|
|
8
8
|
class_timeout 30
|
9
9
|
class_memory 1024
|
10
|
+
class_iam_policy(
|
11
|
+
{
|
12
|
+
sid: "Statement1",
|
13
|
+
action: ["logs:*"],
|
14
|
+
effect: "Allow",
|
15
|
+
resource: "arn:aws:logs:#{Jets.aws.region}:#{Jets.aws.account}:log-group:#{Jets.config.project_namespace}-*",
|
16
|
+
},
|
17
|
+
{
|
18
|
+
sid: "Statement2",
|
19
|
+
action: ["lambda:InvokeFunction", "lambda:InvokeAsync"],
|
20
|
+
effect: "Allow",
|
21
|
+
resource: "arn:aws:lambda:#{Jets.aws.region}:#{Jets.aws.account}:function:#{Jets.config.project_namespace}-*",
|
22
|
+
}
|
23
|
+
)
|
10
24
|
|
11
25
|
unless Jets::Commands::Build.poly_only?
|
12
26
|
torching ? rate(PREWARM_RATE) : disable(true)
|
data/lib/jets/lambda/dsl.rb
CHANGED
@@ -76,6 +76,24 @@ module Jets::Lambda::Dsl
|
|
76
76
|
end
|
77
77
|
alias_method :props, :properties
|
78
78
|
|
79
|
+
# definitions: one more many definitions
|
80
|
+
def class_iam_policy(*definitions)
|
81
|
+
if definitions.empty?
|
82
|
+
@class_iam_policy
|
83
|
+
else
|
84
|
+
@class_iam_policy = definitions.flatten
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# definitions: one more many definitions
|
89
|
+
def iam_policy(*definitions)
|
90
|
+
if definitions.empty?
|
91
|
+
@iam_policy
|
92
|
+
else
|
93
|
+
@iam_policy = definitions.flatten
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
79
97
|
# meth is a Symbol
|
80
98
|
def method_added(meth)
|
81
99
|
return if %w[initialize method_missing].include?(meth.to_s)
|
@@ -89,7 +107,7 @@ module Jets::Lambda::Dsl
|
|
89
107
|
# We adjust the class name when we build the functions later in
|
90
108
|
# FunctionContstructor#adjust_tasks.
|
91
109
|
all_tasks[meth] = Jets::Lambda::Task.new(self.name, meth,
|
92
|
-
properties: @properties, lang: lang)
|
110
|
+
properties: @properties, iam_policy: @iam_policy, lang: lang)
|
93
111
|
|
94
112
|
# Done storing options, clear out for the next added method.
|
95
113
|
clear_properties
|
@@ -106,6 +124,7 @@ module Jets::Lambda::Dsl
|
|
106
124
|
|
107
125
|
def clear_properties
|
108
126
|
@properties = nil
|
127
|
+
@iam_policy = nil
|
109
128
|
end
|
110
129
|
|
111
130
|
# Returns the all tasks for this class with their method names as keys.
|
data/lib/jets/lambda/task.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
class Jets::Lambda::Task
|
2
2
|
attr_accessor :class_name, :type
|
3
|
-
attr_reader :meth, :properties, :lang
|
3
|
+
attr_reader :meth, :properties, :iam_policy, :lang
|
4
4
|
def initialize(class_name, meth, options={})
|
5
5
|
@class_name = class_name.to_s # use at EventsRuleMapper#full_task_name
|
6
6
|
@meth = meth
|
7
7
|
@options = options
|
8
8
|
@type = options[:type] || get_type # controller, job, or function
|
9
9
|
@properties = options[:properties] || {}
|
10
|
+
@iam_policy = options[:iam_policy]
|
10
11
|
@lang = options[:lang] || :ruby
|
11
12
|
end
|
12
13
|
|
data/lib/jets/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -400,6 +400,7 @@ files:
|
|
400
400
|
- lib/jets.rb
|
401
401
|
- lib/jets/application.rb
|
402
402
|
- lib/jets/application/middleware.rb
|
403
|
+
- lib/jets/aws_info.rb
|
403
404
|
- lib/jets/aws_services.rb
|
404
405
|
- lib/jets/booter.rb
|
405
406
|
- lib/jets/builders.rb
|
@@ -423,6 +424,11 @@ files:
|
|
423
424
|
- lib/jets/cfn/template_builders/function_properties/node_builder.rb
|
424
425
|
- lib/jets/cfn/template_builders/function_properties/python_builder.rb
|
425
426
|
- lib/jets/cfn/template_builders/function_properties/ruby_builder.rb
|
427
|
+
- lib/jets/cfn/template_builders/iam_policy.rb
|
428
|
+
- lib/jets/cfn/template_builders/iam_policy/application_policy.rb
|
429
|
+
- lib/jets/cfn/template_builders/iam_policy/base_policy.rb
|
430
|
+
- lib/jets/cfn/template_builders/iam_policy/class_policy.rb
|
431
|
+
- lib/jets/cfn/template_builders/iam_policy/function_policy.rb
|
426
432
|
- lib/jets/cfn/template_builders/interface.rb
|
427
433
|
- lib/jets/cfn/template_builders/job_builder.rb
|
428
434
|
- lib/jets/cfn/template_builders/parent_builder.rb
|
@@ -438,6 +444,11 @@ files:
|
|
438
444
|
- lib/jets/cfn/template_mappers/function_mapper.rb
|
439
445
|
- lib/jets/cfn/template_mappers/gateway_method_mapper.rb
|
440
446
|
- lib/jets/cfn/template_mappers/gateway_resource_mapper.rb
|
447
|
+
- lib/jets/cfn/template_mappers/iam_policy.rb
|
448
|
+
- lib/jets/cfn/template_mappers/iam_policy/application_policy_mapper.rb
|
449
|
+
- lib/jets/cfn/template_mappers/iam_policy/base_policy_mapper.rb
|
450
|
+
- lib/jets/cfn/template_mappers/iam_policy/class_policy_mapper.rb
|
451
|
+
- lib/jets/cfn/template_mappers/iam_policy/function_policy_mapper.rb
|
441
452
|
- lib/jets/cfn/template_mappers/job_mapper.rb
|
442
453
|
- lib/jets/cfn/template_mappers/lambda_function_mapper.rb
|
443
454
|
- lib/jets/cfn/template_mappers/rule_mapper.rb
|