jets 0.8.18 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +0 -3
  3. data/CHANGELOG.md +20 -1
  4. data/Gemfile.lock +6 -2
  5. data/README/prerelease.md +6 -0
  6. data/README/testing.md +41 -0
  7. data/Rakefile +9 -1
  8. data/jets.gemspec +1 -0
  9. data/lib/jets.rb +17 -18
  10. data/lib/jets/application.rb +26 -3
  11. data/lib/jets/aws_services.rb +26 -59
  12. data/lib/jets/aws_services/stack_status.rb +52 -0
  13. data/lib/jets/builders.rb +3 -2
  14. data/lib/jets/builders/handler_generator.rb +38 -2
  15. data/lib/jets/builders/shared_deducer.rb +32 -0
  16. data/lib/jets/cfn/builders.rb +3 -1
  17. data/lib/jets/cfn/builders/api_deployment_builder.rb +1 -1
  18. data/lib/jets/cfn/builders/api_gateway_builder.rb +1 -1
  19. data/lib/jets/cfn/builders/base_child_builder.rb +37 -7
  20. data/lib/jets/cfn/builders/controller_builder.rb +6 -1
  21. data/lib/jets/cfn/builders/function_builder.rb +5 -0
  22. data/lib/jets/cfn/builders/interface.rb +5 -6
  23. data/lib/jets/cfn/builders/job_builder.rb +5 -0
  24. data/lib/jets/cfn/builders/parent_builder.rb +17 -16
  25. data/lib/jets/cfn/builders/rule_builder.rb +6 -1
  26. data/lib/jets/cfn/builders/shared_builder.rb +14 -0
  27. data/lib/jets/commands.rb +9 -8
  28. data/lib/jets/commands/build.rb +36 -14
  29. data/lib/jets/commands/console.rb +1 -0
  30. data/lib/jets/commands/help/runner.md +17 -0
  31. data/lib/jets/commands/main.rb +7 -0
  32. data/lib/jets/commands/new.rb +39 -19
  33. data/lib/jets/commands/runner.rb +18 -0
  34. data/lib/jets/commands/sequence.rb +27 -1
  35. data/lib/jets/commands/templates/skeleton/.rspec +3 -0
  36. data/lib/jets/commands/templates/skeleton/Gemfile.tt +0 -1
  37. data/lib/jets/commands/templates/skeleton/app/jobs/application_job.rb +2 -0
  38. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +2 -1
  39. data/lib/jets/commands/templates/skeleton/config/routes.rb +5 -1
  40. data/lib/jets/commands/templates/skeleton/spec/spec_helper.rb.tt +5 -4
  41. data/lib/jets/core.rb +8 -6
  42. data/lib/jets/default/application.rb +1 -0
  43. data/lib/jets/generator.rb +1 -1
  44. data/lib/jets/inflections.rb +23 -0
  45. data/lib/jets/job/dsl.rb +69 -47
  46. data/lib/jets/klass.rb +6 -1
  47. data/lib/jets/lambda/dsl.rb +102 -34
  48. data/lib/jets/lambda/function_constructor.rb +2 -2
  49. data/lib/jets/lambda/task.rb +10 -5
  50. data/lib/jets/naming.rb +13 -2
  51. data/lib/jets/processors/deducer.rb +13 -2
  52. data/lib/jets/processors/main_processor.rb +1 -1
  53. data/lib/jets/rails_overrides.rb +1 -1
  54. data/lib/jets/resource.rb +20 -5
  55. data/lib/jets/resource/api_gateway/deployment.rb +0 -1
  56. data/lib/jets/resource/associated.rb +26 -0
  57. data/lib/jets/resource/base.rb +12 -0
  58. data/lib/jets/resource/child_stack.rb +2 -0
  59. data/lib/jets/resource/child_stack/api_deployment.rb +9 -15
  60. data/lib/jets/resource/child_stack/api_gateway.rb +8 -8
  61. data/lib/jets/resource/child_stack/app_class.rb +41 -16
  62. data/lib/jets/resource/child_stack/base.rb +24 -0
  63. data/lib/jets/resource/child_stack/shared.rb +90 -0
  64. data/lib/jets/resource/config.rb +4 -0
  65. data/lib/jets/resource/config/config_rule.rb +66 -0
  66. data/lib/jets/resource/config/managed_rule.rb +15 -0
  67. data/lib/jets/resource/events.rb +3 -0
  68. data/lib/jets/resource/events/rule.rb +31 -0
  69. data/lib/jets/resource/iam/application_role.rb +2 -2
  70. data/lib/jets/resource/iam/base_role_definition.rb +4 -2
  71. data/lib/jets/resource/iam/class_role.rb +50 -2
  72. data/lib/jets/resource/iam/function_role.rb +28 -0
  73. data/lib/jets/resource/iam/policy_document.rb +0 -4
  74. data/lib/jets/resource/permission.rb +12 -6
  75. data/lib/jets/resource/replacer.rb +4 -0
  76. data/lib/jets/resource/sns.rb +3 -0
  77. data/lib/jets/resource/standardizer.rb +42 -0
  78. data/lib/jets/router.rb +9 -1
  79. data/lib/jets/rule/dsl.rb +51 -78
  80. data/lib/jets/stack.rb +105 -0
  81. data/lib/jets/stack/builder.rb +38 -0
  82. data/lib/jets/stack/definition.rb +50 -0
  83. data/lib/jets/stack/function.rb +60 -0
  84. data/lib/jets/stack/main.rb +5 -0
  85. data/lib/jets/stack/main/dsl.rb +33 -0
  86. data/lib/jets/stack/main/extensions/base.rb +45 -0
  87. data/lib/jets/stack/main/extensions/cloudwatch.rb +19 -0
  88. data/lib/jets/stack/main/extensions/lambda.rb +69 -0
  89. data/lib/jets/stack/main/extensions/sns.rb +12 -0
  90. data/lib/jets/stack/main/extensions/sqs.rb +8 -0
  91. data/lib/jets/stack/output.rb +38 -0
  92. data/lib/jets/stack/output/dsl.rb +19 -0
  93. data/lib/jets/stack/output/lookup.rb +36 -0
  94. data/lib/jets/stack/parameter.rb +38 -0
  95. data/lib/jets/stack/parameter/dsl.rb +42 -0
  96. data/lib/jets/stack/resource.rb +30 -0
  97. data/lib/jets/stack/resource/dsl.rb +19 -0
  98. data/lib/jets/version.rb +1 -1
  99. metadata +53 -4
  100. data/support/clean +0 -3
  101. data/support/console +0 -3
@@ -1,9 +1,10 @@
1
+ # Implements:
2
+ #
3
+ # definition
4
+ # template_filename
5
+ #
1
6
  module Jets::Resource::ChildStack
2
- class ApiGateway < Jets::Resource::Base
3
- def initialize(s3_bucket)
4
- @s3_bucket = s3_bucket
5
- end
6
-
7
+ class ApiGateway < Base
7
8
  def definition
8
9
  {
9
10
  api_gateway: {
@@ -21,9 +22,8 @@ module Jets::Resource::ChildStack
21
22
  }
22
23
  end
23
24
 
24
- def template_url
25
- path = File.basename("#{Jets.config.project_namespace}-api-gateway.yml")
26
- "https://s3.amazonaws.com/#{@s3_bucket}/jets/cfn-templates/#{path}"
25
+ def template_filename
26
+ "#{Jets.config.project_namespace}-api-gateway.yml"
27
27
  end
28
28
  end
29
29
  end
@@ -1,13 +1,18 @@
1
+ # Implements:
2
+ #
3
+ # definition
4
+ # template_filename
5
+ #
1
6
  module Jets::Resource::ChildStack
2
- class AppClass < Jets::Resource::Base
3
- def initialize(path, s3_bucket)
4
- @path = path
5
- @s3_bucket = s3_bucket
7
+ class AppClass < Base
8
+ def initialize(s3_bucket, options={})
9
+ super
10
+ @path = options[:path]
6
11
  end
7
12
 
8
13
  def definition
9
14
  logical_id = app_logical_id
10
- {
15
+ defintion = {
11
16
  logical_id => {
12
17
  type: "AWS::CloudFormation::Stack",
13
18
  properties: {
@@ -16,6 +21,32 @@ module Jets::Resource::ChildStack
16
21
  }
17
22
  }
18
23
  }
24
+ defintion[logical_id][:depends_on] = depends_on if depends_on
25
+ defintion
26
+ end
27
+
28
+ def depends_on
29
+ klass = current_app_class.constantize
30
+ return unless klass.depends_on
31
+
32
+ klass.depends_on.map do |shared_stack|
33
+ shared_stack.to_s.camelize # logical_id
34
+ end
35
+ end
36
+
37
+ def depends_on_params
38
+ params = {}
39
+ depends_on.each do |dependency|
40
+ dependency_outputs(dependency).each do |output|
41
+ dependency_class = dependency.to_s.classify
42
+ params[output] = "!GetAtt #{dependency_class}.Outputs.#{output}"
43
+ end
44
+ end
45
+ params
46
+ end
47
+
48
+ def dependency_outputs(dependency)
49
+ dependency.to_s.classify.constantize.output_keys
19
50
  end
20
51
 
21
52
  def parameters
@@ -24,6 +55,7 @@ module Jets::Resource::ChildStack
24
55
  S3Bucket: "!Ref S3Bucket",
25
56
  }
26
57
  common.merge!(controller_params) if controller?
58
+ common.merge!(depends_on_params) if depends_on
27
59
  common
28
60
  end
29
61
 
@@ -51,31 +83,24 @@ module Jets::Resource::ChildStack
51
83
  end
52
84
 
53
85
  def current_app_class
54
- templates_prefix = "#{Jets::Naming.template_path_prefix}-"
86
+ templates_prefix = "#{Jets::Naming.template_path_prefix}-app-"
55
87
  @path.sub(templates_prefix, '')
56
88
  .sub(/\.yml$/,'')
57
89
  .gsub('-','/')
58
90
  .classify
59
91
  end
60
92
 
61
- def outputs
62
- {
63
- logical_id => "!Ref #{logical_id}",
64
- }
65
- end
66
-
67
- # Dont name logical id because that is in Jets::Resource
68
93
  # map the path to a camelized logical_id. Example:
69
94
  # /tmp/jets/demo/templates/demo-dev-2-posts_controller.yml to
70
95
  # PostsController
71
96
  def app_logical_id
72
- regexp = Regexp.new(".*#{Jets.config.project_namespace}-")
97
+ regexp = Regexp.new(".*#{Jets.config.project_namespace}-app-")
73
98
  controller_name = @path.sub(regexp, '').sub('.yml', '')
74
99
  controller_name.underscore.camelize
75
100
  end
76
101
 
77
- def template_url
78
- "https://s3.amazonaws.com/#{@s3_bucket}/jets/cfn-templates/#{File.basename(@path)}"
102
+ def template_filename
103
+ @path
79
104
  end
80
105
  end
81
106
  end
@@ -0,0 +1,24 @@
1
+ # Inheriting classes should implement:
2
+ #
3
+ # definition
4
+ # template_filename
5
+ #
6
+ module Jets::Resource::ChildStack
7
+ class Base < Jets::Resource::Base
8
+ def initialize(s3_bucket, options={})
9
+ @s3_bucket = s3_bucket
10
+ @options = options
11
+ end
12
+
13
+ def outputs
14
+ {
15
+ logical_id => "!Ref #{logical_id}",
16
+ }
17
+ end
18
+
19
+ def template_url
20
+ basename = File.basename(template_filename)
21
+ "https://s3.amazonaws.com/#{@s3_bucket}/jets/cfn-templates/#{basename}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,90 @@
1
+ # Implements:
2
+ #
3
+ # definition
4
+ # template_filename
5
+ #
6
+ module Jets::Resource::ChildStack
7
+ class Shared < AppClass
8
+ def initialize(s3_bucket, options={})
9
+ super
10
+ @path = options[:path]
11
+ end
12
+
13
+ def definition
14
+ logical_id = shared_logical_id
15
+ definition = {
16
+ logical_id => {
17
+ type: "AWS::CloudFormation::Stack",
18
+ properties: child_properties
19
+ }
20
+ }
21
+ definition[logical_id][:depends_on] = depends_on if depends_on
22
+ definition
23
+ end
24
+
25
+ def child_properties
26
+ props = {
27
+ template_url: template_url,
28
+ }
29
+
30
+ props[:parameters] = common_parameters # common child parameters
31
+ # add depends on parameters
32
+ depends_on.each do |dependency|
33
+ dependency_outputs(dependency).each do |output|
34
+ dependency_class = dependency.to_s.classify
35
+ props[:parameters][output] = "!GetAtt #{dependency_class}.Outputs.#{output}"
36
+ end
37
+ end if depends_on
38
+
39
+ props
40
+ end
41
+
42
+ def common_parameters
43
+ {
44
+ IamRole: "!GetAtt IamRole.Arn",
45
+ S3Bucket: "!Ref S3Bucket",
46
+ }
47
+ end
48
+
49
+ # Returns output keys associated with the stack. They are the resource logical ids.
50
+ def dependency_outputs(dependency)
51
+ dependency.to_s.classify.constantize.output_keys
52
+ end
53
+
54
+ def depends_on
55
+ return unless current_shared_class.depends_on
56
+ current_shared_class.depends_on.map { |x| x.to_s.singularize.camelize }
57
+ end
58
+
59
+ # map the path to a camelized logical_id. Example:
60
+ # /tmp/jets/demo/templates/demo-dev-2-shared-resources.yml to
61
+ # PostsController
62
+ def shared_logical_id
63
+ regexp = Regexp.new(".*#{Jets.config.project_namespace}-shared-") # remove the shared
64
+ shared_name = @path.sub(regexp, '').sub('.yml', '')
65
+ shared_name.underscore.camelize
66
+ end
67
+
68
+ # IE: app/resource.rb => Resource
69
+ # Returns Resource class object in the example
70
+ def current_shared_class
71
+ templates_prefix = "#{Jets::Naming.template_path_prefix}-shared-"
72
+ @path.sub(templates_prefix, '')
73
+ .sub(/\.yml$/,'')
74
+ .gsub('-','/')
75
+ .classify
76
+ .constantize # returns actual class
77
+ end
78
+
79
+ # Tells us if there are any resources defined in the shared class.
80
+ #
81
+ # Returns: Boolean
82
+ def resources?
83
+ current_shared_class.build?
84
+ end
85
+
86
+ def template_filename
87
+ "#{Jets.config.project_namespace}-shared-#{current_shared_class.to_s.underscore}.yml"
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,4 @@
1
+ module Jets::Resource::Config
2
+ autoload :ConfigRule, 'jets/resource/config/config_rule'
3
+ autoload :ManagedRule, 'jets/resource/config/managed_rule'
4
+ end
@@ -0,0 +1,66 @@
1
+ module Jets::Resource::Config
2
+ class ConfigRule < Jets::Resource::Base
3
+ def initialize(app_class, meth, props={})
4
+ @app_class = app_class.to_s
5
+ @meth = meth
6
+ @props = props # associated_properties from dsl.rb
7
+ end
8
+
9
+ def definition
10
+ {
11
+ config_rule_logical_id => {
12
+ type: "AWS::Config::ConfigRule",
13
+ properties: definition_properties,
14
+ }
15
+ }
16
+ end
17
+
18
+ # Do not name this method properties, that is a computed method of `Jets::Resource::Base`
19
+ def definition_properties
20
+ {
21
+ config_rule_name: config_rule_name,
22
+ source: {
23
+ owner: "CUSTOM_LAMBDA",
24
+ source_identifier: "!GetAtt {namespace}LambdaFunction.Arn",
25
+ source_details: [
26
+ {
27
+ event_source: "aws.config",
28
+ message_type: "ConfigurationItemChangeNotification"
29
+ },
30
+ {
31
+ event_source: "aws.config",
32
+ message_type: "OversizedConfigurationItemChangeNotification"
33
+ }
34
+ ]
35
+ },
36
+ }.deep_merge(@props)
37
+ end
38
+
39
+ def config_rule_logical_id
40
+ "{namespace}_config_rule"
41
+ end
42
+
43
+ def config_rule_name
44
+ app_class = @app_class.underscore.gsub(/_rule$/,'')
45
+ ns = namespace
46
+ ns = nil if ns == false # for compact
47
+ [ns, "#{app_class}_#{@meth}"].compact.join('_').dasherize
48
+ end
49
+
50
+ def namespace
51
+ namespace = nil
52
+ klass = @app_class.constantize
53
+ while klass != Jets::Lambda::Functions
54
+ namespace = klass.rule_namespace
55
+ break if namespace or namespace == false
56
+ klass = klass.superclass
57
+ end
58
+
59
+ if namespace.nil?
60
+ Jets.config.project_namespace
61
+ else
62
+ namespace
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
1
+ # ManagedRule is just different enough to be a separate class vs being part of the
2
+ # ConfigRule class itself.
3
+ module Jets::Resource::Config
4
+ class ManagedRule < ConfigRule
5
+ def definition_properties
6
+ {
7
+ config_rule_name: config_rule_name,
8
+ source: {
9
+ owner: "AWS",
10
+ source_identifier: @meth.upcase,
11
+ },
12
+ }.deep_merge(@props)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Jets::Resource::Events
2
+ autoload :Rule, 'jets/resource/events/rule'
3
+ end
@@ -0,0 +1,31 @@
1
+ module Jets::Resource::Events
2
+ class Rule < Jets::Resource::Base
3
+ def initialize(props)
4
+ @props = props # associated_properties from dsl.rb
5
+ end
6
+
7
+ def definition
8
+ {
9
+ rule_logical_id => {
10
+ type: "AWS::Events::Rule",
11
+ properties: merged_properties
12
+ }
13
+ }
14
+ end
15
+
16
+ # Do not name this method properties, that is a computed method of `Jets::Resource::Base`
17
+ def merged_properties
18
+ {
19
+ state: "ENABLED",
20
+ targets: [{
21
+ arn: "!GetAtt {namespace}LambdaFunction.Arn",
22
+ id: "{namespace}RuleTarget"
23
+ }]
24
+ }.deep_merge(@props)
25
+ end
26
+
27
+ def rule_logical_id
28
+ "{namespace}_events_rule"
29
+ end
30
+ end
31
+ end
@@ -4,10 +4,10 @@ module Jets::Resource::Iam
4
4
 
5
5
  def initialize
6
6
  @policy_definitions = Jets.config.iam_policy # config.iam_policy contains definitions
7
- @policy_definitions = [@policy_definitions].flatten if @policy_definitions
7
+ @policy_definitions = @policy_definitions ? [@policy_definitions].flatten : []
8
8
 
9
9
  @managed_policy_definitions = Jets.config.managed_iam_policy # config.managed_iam_policy contains definitions
10
- @managed_policy_definitions = [@managed_policy_definitions].flatten if @managed_policy_definitions
10
+ @managed_policy_definitions = @managed_policy_definitions ? [@managed_policy_definitions].flatten : []
11
11
  end
12
12
 
13
13
  def role_logical_id
@@ -1,5 +1,7 @@
1
1
  module Jets::Resource::Iam
2
2
  module BaseRoleDefinition
3
+ attr_reader :policy_definitions, :managed_policy_definitions
4
+
3
5
  def definition
4
6
  logical_id = role_logical_id
5
7
 
@@ -34,11 +36,11 @@ module Jets::Resource::Iam
34
36
  end
35
37
 
36
38
  def policy_document
37
- PolicyDocument.new(@policy_definitions).policy_document
39
+ PolicyDocument.new(@policy_definitions.uniq).policy_document
38
40
  end
39
41
 
40
42
  def managed_policy_arns
41
- ManagedPolicy.new(@managed_policy_definitions).arns
43
+ ManagedPolicy.new(@managed_policy_definitions.uniq).arns
42
44
  end
43
45
  end
44
46
  end
@@ -4,8 +4,8 @@ module Jets::Resource::Iam
4
4
 
5
5
  def initialize(app_class)
6
6
  @app_class = app_class.to_s # IE: PostsController, HardJob, Hello, HelloFunction
7
- @policy_definitions = app_class.class_iam_policy || [] # class_iam_policy contains definitions
8
- @managed_policy_definitions = app_class.class_managed_iam_policy || [] # class_managed_iam_policy contains definitions
7
+ @policy_definitions = lookup_iam_policies
8
+ @managed_policy_definitions = lookup_managed_iam_policies
9
9
  end
10
10
 
11
11
  def role_logical_id
@@ -22,5 +22,53 @@ module Jets::Resource::Iam
22
22
  namespace: @app_class.gsub('::','').camelize, # camelized because can be used as value
23
23
  }
24
24
  end
25
+
26
+ def policy_document
27
+ # Handles precedence inheritance from the ApplicationRole to the ClassRole
28
+ @policy_definitions += application_role.policy_definitions if inherit?
29
+ super
30
+ end
31
+
32
+ def managed_policy_arns
33
+ @managed_policy_definitions += application_role.managed_policy_definitions if inherit?
34
+ super
35
+ end
36
+
37
+ # There are 2 types of inheritance: from superclasses and from higher precedence policies.
38
+ # This one manages the inheritance for higher precedence policies.
39
+ def inherit?
40
+ !@policy_definitions.empty? || !@managed_policy_definitions.empty?
41
+ end
42
+
43
+ def application_role
44
+ Jets::Resource::Iam::ApplicationRole.new
45
+ end
46
+ memoize :application_role
47
+
48
+ # Accounts for inherited class_managed_iam_policy from superclasses
49
+ def lookup_managed_iam_policies
50
+ all_classes.map do |k|
51
+ k.class_managed_iam_policy # class_managed_iam_policy contains definitions
52
+ end.uniq
53
+ end
54
+
55
+ # Accounts for inherited class_iam_policies from superclasses
56
+ def lookup_iam_policies
57
+ all_classes.map do |k|
58
+ k.class_iam_policy # class_iam_policy contains definitions
59
+ end.uniq
60
+ end
61
+
62
+ # Class heirachry in top to down order
63
+ def all_classes
64
+ klass = @app_class.constantize
65
+ all_classes = []
66
+ while klass != Object
67
+ all_classes << klass
68
+ klass = klass.superclass
69
+ end
70
+ all_classes.reverse
71
+ end
72
+ memoize :all_classes
25
73
  end
26
74
  end