jets 0.8.18 → 0.9.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/.gitmodules +0 -3
- data/CHANGELOG.md +20 -1
- data/Gemfile.lock +6 -2
- data/README/prerelease.md +6 -0
- data/README/testing.md +41 -0
- data/Rakefile +9 -1
- data/jets.gemspec +1 -0
- data/lib/jets.rb +17 -18
- data/lib/jets/application.rb +26 -3
- data/lib/jets/aws_services.rb +26 -59
- data/lib/jets/aws_services/stack_status.rb +52 -0
- data/lib/jets/builders.rb +3 -2
- data/lib/jets/builders/handler_generator.rb +38 -2
- data/lib/jets/builders/shared_deducer.rb +32 -0
- data/lib/jets/cfn/builders.rb +3 -1
- data/lib/jets/cfn/builders/api_deployment_builder.rb +1 -1
- data/lib/jets/cfn/builders/api_gateway_builder.rb +1 -1
- data/lib/jets/cfn/builders/base_child_builder.rb +37 -7
- data/lib/jets/cfn/builders/controller_builder.rb +6 -1
- data/lib/jets/cfn/builders/function_builder.rb +5 -0
- data/lib/jets/cfn/builders/interface.rb +5 -6
- data/lib/jets/cfn/builders/job_builder.rb +5 -0
- data/lib/jets/cfn/builders/parent_builder.rb +17 -16
- data/lib/jets/cfn/builders/rule_builder.rb +6 -1
- data/lib/jets/cfn/builders/shared_builder.rb +14 -0
- data/lib/jets/commands.rb +9 -8
- data/lib/jets/commands/build.rb +36 -14
- data/lib/jets/commands/console.rb +1 -0
- data/lib/jets/commands/help/runner.md +17 -0
- data/lib/jets/commands/main.rb +7 -0
- data/lib/jets/commands/new.rb +39 -19
- data/lib/jets/commands/runner.rb +18 -0
- data/lib/jets/commands/sequence.rb +27 -1
- data/lib/jets/commands/templates/skeleton/.rspec +3 -0
- data/lib/jets/commands/templates/skeleton/Gemfile.tt +0 -1
- data/lib/jets/commands/templates/skeleton/app/jobs/application_job.rb +2 -0
- data/lib/jets/commands/templates/skeleton/config/application.rb.tt +2 -1
- data/lib/jets/commands/templates/skeleton/config/routes.rb +5 -1
- data/lib/jets/commands/templates/skeleton/spec/spec_helper.rb.tt +5 -4
- data/lib/jets/core.rb +8 -6
- data/lib/jets/default/application.rb +1 -0
- data/lib/jets/generator.rb +1 -1
- data/lib/jets/inflections.rb +23 -0
- data/lib/jets/job/dsl.rb +69 -47
- data/lib/jets/klass.rb +6 -1
- data/lib/jets/lambda/dsl.rb +102 -34
- data/lib/jets/lambda/function_constructor.rb +2 -2
- data/lib/jets/lambda/task.rb +10 -5
- data/lib/jets/naming.rb +13 -2
- data/lib/jets/processors/deducer.rb +13 -2
- data/lib/jets/processors/main_processor.rb +1 -1
- data/lib/jets/rails_overrides.rb +1 -1
- data/lib/jets/resource.rb +20 -5
- data/lib/jets/resource/api_gateway/deployment.rb +0 -1
- data/lib/jets/resource/associated.rb +26 -0
- data/lib/jets/resource/base.rb +12 -0
- data/lib/jets/resource/child_stack.rb +2 -0
- data/lib/jets/resource/child_stack/api_deployment.rb +9 -15
- data/lib/jets/resource/child_stack/api_gateway.rb +8 -8
- data/lib/jets/resource/child_stack/app_class.rb +41 -16
- data/lib/jets/resource/child_stack/base.rb +24 -0
- data/lib/jets/resource/child_stack/shared.rb +90 -0
- data/lib/jets/resource/config.rb +4 -0
- data/lib/jets/resource/config/config_rule.rb +66 -0
- data/lib/jets/resource/config/managed_rule.rb +15 -0
- data/lib/jets/resource/events.rb +3 -0
- data/lib/jets/resource/events/rule.rb +31 -0
- data/lib/jets/resource/iam/application_role.rb +2 -2
- data/lib/jets/resource/iam/base_role_definition.rb +4 -2
- data/lib/jets/resource/iam/class_role.rb +50 -2
- data/lib/jets/resource/iam/function_role.rb +28 -0
- data/lib/jets/resource/iam/policy_document.rb +0 -4
- data/lib/jets/resource/permission.rb +12 -6
- data/lib/jets/resource/replacer.rb +4 -0
- data/lib/jets/resource/sns.rb +3 -0
- data/lib/jets/resource/standardizer.rb +42 -0
- data/lib/jets/router.rb +9 -1
- data/lib/jets/rule/dsl.rb +51 -78
- data/lib/jets/stack.rb +105 -0
- data/lib/jets/stack/builder.rb +38 -0
- data/lib/jets/stack/definition.rb +50 -0
- data/lib/jets/stack/function.rb +60 -0
- data/lib/jets/stack/main.rb +5 -0
- data/lib/jets/stack/main/dsl.rb +33 -0
- data/lib/jets/stack/main/extensions/base.rb +45 -0
- data/lib/jets/stack/main/extensions/cloudwatch.rb +19 -0
- data/lib/jets/stack/main/extensions/lambda.rb +69 -0
- data/lib/jets/stack/main/extensions/sns.rb +12 -0
- data/lib/jets/stack/main/extensions/sqs.rb +8 -0
- data/lib/jets/stack/output.rb +38 -0
- data/lib/jets/stack/output/dsl.rb +19 -0
- data/lib/jets/stack/output/lookup.rb +36 -0
- data/lib/jets/stack/parameter.rb +38 -0
- data/lib/jets/stack/parameter/dsl.rb +42 -0
- data/lib/jets/stack/resource.rb +30 -0
- data/lib/jets/stack/resource/dsl.rb +19 -0
- data/lib/jets/version.rb +1 -1
- metadata +53 -4
- data/support/clean +0 -3
- data/support/console +0 -3
@@ -0,0 +1,38 @@
|
|
1
|
+
class Jets::Stack
|
2
|
+
class Builder
|
3
|
+
extend Memoist
|
4
|
+
|
5
|
+
def initialize(stack)
|
6
|
+
@stack = stack
|
7
|
+
@template = {} # will build this structure up
|
8
|
+
end
|
9
|
+
|
10
|
+
def template
|
11
|
+
build_section(:parameters)
|
12
|
+
build_section(:resources)
|
13
|
+
build_section(:outputs)
|
14
|
+
Jets::Camelizer.transform(@template)
|
15
|
+
end
|
16
|
+
memoize :template
|
17
|
+
|
18
|
+
def build_section(section)
|
19
|
+
elements = build_elements(section)
|
20
|
+
@template[section] = elements if elements
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_elements(section)
|
24
|
+
# s is a "section element". Examples:
|
25
|
+
#
|
26
|
+
# Jets::Stack::Parameter
|
27
|
+
# Jets::Stack::Resource
|
28
|
+
# Jets::Stack::Output
|
29
|
+
#
|
30
|
+
section_elements = @stack.send(section)
|
31
|
+
return unless section_elements
|
32
|
+
|
33
|
+
section_elements.inject({}) do |template_section, s|
|
34
|
+
template_section.merge(s.template)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Class that include Definition should implement:
|
2
|
+
#
|
3
|
+
# template - method should use @definition to build a CloudFormation template section
|
4
|
+
#
|
5
|
+
class Jets::Stack
|
6
|
+
module Definition
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
# Example of usage that leads here:
|
10
|
+
#
|
11
|
+
# Parameter.new(self, *definition).register
|
12
|
+
#
|
13
|
+
# Which is defined in parameter/dsl.rb
|
14
|
+
#
|
15
|
+
# Example subclass: ExampleStack < Jets::Stack
|
16
|
+
def initialize(subclass, *definition)
|
17
|
+
@subclass = subclass.to_s # important to use to_s, dont want the object as keys in @definitions
|
18
|
+
@definition = definition.flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
def register
|
22
|
+
self.class.register(@subclass, *@definition)
|
23
|
+
end
|
24
|
+
|
25
|
+
def camelize(attributes)
|
26
|
+
Jets::Camelizer.transform(attributes)
|
27
|
+
end
|
28
|
+
|
29
|
+
class_methods do
|
30
|
+
def register(subclass, *definition)
|
31
|
+
@definitions ||= {}
|
32
|
+
@definitions[subclass.to_s] ||= []
|
33
|
+
# Create instance of the CloudFormation section class and register it. Examples:
|
34
|
+
# Stack::Parameter.new(definition)
|
35
|
+
# Stack::Resource.new(definition)
|
36
|
+
# Stack::Output.new(definition)
|
37
|
+
@definitions[subclass.to_s] << new(subclass, definition)
|
38
|
+
end
|
39
|
+
|
40
|
+
def definitions(subclass)
|
41
|
+
@definitions ||= {}
|
42
|
+
@definitions[subclass.to_s]
|
43
|
+
end
|
44
|
+
|
45
|
+
def all_definitions
|
46
|
+
@definitions
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Jets::Stack
|
2
|
+
class Function
|
3
|
+
extend Memoist
|
4
|
+
|
5
|
+
attr_reader :template
|
6
|
+
def initialize(template)
|
7
|
+
@template = template
|
8
|
+
end
|
9
|
+
|
10
|
+
def meth
|
11
|
+
attributes = @template.values.first
|
12
|
+
handler = attributes['Properties']['Handler']
|
13
|
+
handler.split('.').last
|
14
|
+
end
|
15
|
+
|
16
|
+
def lang
|
17
|
+
if source_file
|
18
|
+
# Detect language from file extension
|
19
|
+
ext = File.extname(source_file).sub(/^\./,'').to_sym
|
20
|
+
lang_map[ext]
|
21
|
+
else
|
22
|
+
puts "WARN: Unable to find a source file for function. Looked at: #{search_expression}".colorize(:yellow)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def lang_map
|
27
|
+
{
|
28
|
+
rb: :ruby,
|
29
|
+
py: :python,
|
30
|
+
js: :node,
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def source_file
|
35
|
+
Dir.glob(search_expression).first
|
36
|
+
end
|
37
|
+
memoize :source_file
|
38
|
+
|
39
|
+
def search_expression
|
40
|
+
attributes = @template.values.first
|
41
|
+
handler = attributes['Properties']['Handler']
|
42
|
+
search_expression = handler.split('.')[0..-2].join('.') + '.*'
|
43
|
+
search_expression.sub('handlers/shared/', "#{Jets.root}app/shared/")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Relative path
|
47
|
+
# app/shared/functions/kevin.py => handlers/shared/functions/kevin.py
|
48
|
+
def handler_dest
|
49
|
+
return unless source_file
|
50
|
+
|
51
|
+
dest = source_file.sub(%r{.*/app/}, "handlers/")
|
52
|
+
if lang == :ruby
|
53
|
+
filename = dest.split('.').first
|
54
|
+
filename + '.js' # change extension to .js because ruby uses a node shim
|
55
|
+
else
|
56
|
+
dest
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Jets::Stack
|
2
|
+
class Main
|
3
|
+
module Dsl
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
autoload :Base, 'jets/stack/main/extensions/base'
|
6
|
+
autoload :Cloudwatch, 'jets/stack/main/extensions/cloudwatch'
|
7
|
+
autoload :Lambda, 'jets/stack/main/extensions/lambda'
|
8
|
+
autoload :Sns, 'jets/stack/main/extensions/sns'
|
9
|
+
autoload :Sqs, 'jets/stack/main/extensions/sqs'
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
include Base
|
13
|
+
include Cloudwatch
|
14
|
+
include Lambda
|
15
|
+
include Sns
|
16
|
+
include Sqs
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base_path = "#{Jets.root}/app/shared/extensions"
|
21
|
+
ActiveSupport::Dependencies.autoload_paths += [base_path]
|
22
|
+
|
23
|
+
Dir.glob("#{base_path}/**/*.rb").each do |path|
|
24
|
+
next unless File.file?(path)
|
25
|
+
|
26
|
+
class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').classify
|
27
|
+
klass = class_name.constantize # autoload
|
28
|
+
base.extend(klass)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Jets::Stack::Main::Dsl
|
2
|
+
module Base
|
3
|
+
def ref(value)
|
4
|
+
"!Ref #{value.to_s.camelize}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def logical_id(value)
|
8
|
+
value.to_s.camelize
|
9
|
+
end
|
10
|
+
|
11
|
+
def depends_on(*stacks)
|
12
|
+
if stacks == []
|
13
|
+
@depends_on
|
14
|
+
else
|
15
|
+
@depends_on ||= []
|
16
|
+
@depends_on += stacks
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Due to `if Jets::Stack.has_resources?` check early on in the bootstraping process
|
21
|
+
# The code has not been built at that point. So we use a placeholder and will replace
|
22
|
+
# the placeholder as part of the cfn template build process after the code has been built
|
23
|
+
# and the code_s3_key with md5 is available.
|
24
|
+
def code_s3_key
|
25
|
+
"code_s3_key_placeholder"
|
26
|
+
end
|
27
|
+
|
28
|
+
# resource(:hello,
|
29
|
+
# function_name: "hello",
|
30
|
+
# code: {
|
31
|
+
# s3_bucket: "!Ref S3Bucket",
|
32
|
+
# s3_key: code_s3_key
|
33
|
+
# },
|
34
|
+
# description: "Hello world",
|
35
|
+
# handler: handler_function("hello.lambda_handler"),
|
36
|
+
# memory_size: 128,
|
37
|
+
# role: "!Ref IamRole",
|
38
|
+
# runtime: "python3.6",
|
39
|
+
# timeout: 20,
|
40
|
+
# )
|
41
|
+
def handler(name)
|
42
|
+
"handlers/shared/functions/#{name}" # generated handler
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Jets::Stack::Main::Dsl
|
2
|
+
module Cloudwatch
|
3
|
+
def cloudwatch_alarm(id, hash={})
|
4
|
+
if hash.key?(:depends_on)
|
5
|
+
attributes = hash # leave structure alone and add type only
|
6
|
+
attributes[:type] = "AWS::CloudWatch::Alarm"
|
7
|
+
else
|
8
|
+
# the attributes are properties
|
9
|
+
properties = hash
|
10
|
+
attributes = {
|
11
|
+
type: "AWS::CloudWatch::Alarm",
|
12
|
+
properties: properties,
|
13
|
+
}
|
14
|
+
end
|
15
|
+
resource(id, attributes)
|
16
|
+
output(id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Jets::Stack::Main::Dsl
|
2
|
+
module Lambda
|
3
|
+
# Example:
|
4
|
+
#
|
5
|
+
# function(:hello,
|
6
|
+
# handler: handler("hello.lambda_hander"),
|
7
|
+
# runtime: "python3.6"
|
8
|
+
# )
|
9
|
+
#
|
10
|
+
# Defaults to ruby. So:
|
11
|
+
#
|
12
|
+
# function(:hello)
|
13
|
+
#
|
14
|
+
# is the same as:
|
15
|
+
#
|
16
|
+
# function(:hello,
|
17
|
+
# handler: handler("hello.hande"),
|
18
|
+
# runtime: :ruby
|
19
|
+
# )
|
20
|
+
#
|
21
|
+
def function(id, props={})
|
22
|
+
# Required: code, handler, role, runtime Docs: https://amzn.to/2pdot7S
|
23
|
+
meth = id.to_s.underscore
|
24
|
+
defaults = {
|
25
|
+
function_name: "#{Jets.config.project_namespace}-#{id.to_s.underscore}",
|
26
|
+
code: {
|
27
|
+
s3_bucket: "!Ref S3Bucket",
|
28
|
+
s3_key: code_s3_key
|
29
|
+
},
|
30
|
+
role: "!Ref IamRole",
|
31
|
+
handler: "#{meth}.handle", # default ruby convention
|
32
|
+
runtime: :ruby,
|
33
|
+
timeout: Jets.config.function.timeout,
|
34
|
+
memory_size: Jets.config.function.memory_size,
|
35
|
+
}
|
36
|
+
props = defaults.merge(props)
|
37
|
+
props[:runtime] = "nodejs8.10" if props[:runtime].to_s == "ruby"
|
38
|
+
props[:handler] = handler(props[:handler])
|
39
|
+
|
40
|
+
resource(id, "AWS::Lambda::Function", props)
|
41
|
+
end
|
42
|
+
alias_method :ruby_function, :function
|
43
|
+
alias_method :lambda_function, :function
|
44
|
+
|
45
|
+
def python_function(id, props={})
|
46
|
+
meth = id.to_s.underscore
|
47
|
+
props[:handler] ||= "#{meth}.lambda_handler" # default python convention
|
48
|
+
props[:runtime] = "python3.6"
|
49
|
+
function(id, props)
|
50
|
+
end
|
51
|
+
|
52
|
+
def node_function(id, props={})
|
53
|
+
meth = id.to_s.underscore
|
54
|
+
props[:handler] ||= "#{meth}.handler" # default python convention
|
55
|
+
props[:runtime] = "node8.10"
|
56
|
+
function(id, props)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Usage:
|
60
|
+
#
|
61
|
+
# permission(:my_permission, principal: "events.amazonaws.com")
|
62
|
+
#
|
63
|
+
def permission(id, props={})
|
64
|
+
defaults = { action: "lambda:InvokeFunction" }
|
65
|
+
props = defaults.merge(props)
|
66
|
+
resource(id, "AWS::Lambda::Permission", props)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Implements:
|
2
|
+
#
|
3
|
+
# template - uses @definition to build a CloudFormation template section
|
4
|
+
#
|
5
|
+
class Jets::Stack
|
6
|
+
class Output
|
7
|
+
autoload :Dsl, "jets/stack/output/dsl"
|
8
|
+
autoload :Lookup, "jets/stack/output/lookup"
|
9
|
+
|
10
|
+
include Definition
|
11
|
+
|
12
|
+
def template
|
13
|
+
camelize(standarize(@definition))
|
14
|
+
end
|
15
|
+
|
16
|
+
# Value is the only required property: https://amzn.to/2xbhmk3
|
17
|
+
def standarize(definition)
|
18
|
+
first, second, _ = definition
|
19
|
+
if definition.size == 1 && first.is_a?(Hash) # long form
|
20
|
+
first # pass through
|
21
|
+
elsif definition.size == 2 && second.is_a?(Hash) # medium form
|
22
|
+
logical_id, properties = first, second
|
23
|
+
{ logical_id => properties }
|
24
|
+
elsif definition.size == 2 && second.is_a?(String) # short form
|
25
|
+
logical_id = first
|
26
|
+
properties = second.is_a?(String) ? { value: second } : {}
|
27
|
+
{ logical_id => properties }
|
28
|
+
elsif definition.size == 1
|
29
|
+
logical_id = first.to_s
|
30
|
+
properties = {value: "!Ref #{logical_id.camelize}"}
|
31
|
+
{ logical_id => properties }
|
32
|
+
else # I dont know what form
|
33
|
+
raise "Invalid form provided. definition #{definition.inspect}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Jets::Stack
|
2
|
+
class Output
|
3
|
+
module Dsl
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def outputs
|
7
|
+
Output.definitions(self.class)
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def output(*definition)
|
12
|
+
# self is subclass is the stack that inherits from Jets::Stack
|
13
|
+
# IE: ExampleStack < Jets::Stack
|
14
|
+
Output.new(self, *definition).register
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Jets::Stack::Output
|
2
|
+
class Lookup
|
3
|
+
include Jets::AwsServices
|
4
|
+
|
5
|
+
def initialize(stack_subclass)
|
6
|
+
@stack_subclass = stack_subclass
|
7
|
+
end
|
8
|
+
|
9
|
+
def output(logical_id)
|
10
|
+
child_stack_id = @stack_subclass.to_s.classify
|
11
|
+
|
12
|
+
stack_arn = shared_stack_arn(child_stack_id)
|
13
|
+
resp = cfn.describe_stacks(stack_name: stack_arn)
|
14
|
+
child = resp.stacks.first
|
15
|
+
return unless child
|
16
|
+
|
17
|
+
output_value(child, logical_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Shared child stack arn
|
21
|
+
def shared_stack_arn(logical_id)
|
22
|
+
parent_stack = Jets.config.project_namespace
|
23
|
+
resp = cfn.describe_stacks(stack_name: parent_stack)
|
24
|
+
parent = resp.stacks.first
|
25
|
+
output_value(parent, logical_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def output_value(stack, key)
|
29
|
+
key = key.to_s.camelize
|
30
|
+
output = stack.outputs.find do |o|
|
31
|
+
o.output_key == key
|
32
|
+
end
|
33
|
+
output&.output_value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|