jets 0.8.0 → 0.8.1

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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +3 -1
  4. data/jets.gemspec +2 -0
  5. data/lib/jets/application.rb +1 -1
  6. data/lib/jets/cfn.rb +1 -2
  7. data/lib/jets/cfn/builders.rb +19 -0
  8. data/lib/jets/cfn/builders/api_deployment_builder.rb +32 -0
  9. data/lib/jets/cfn/{template_builders → builders}/api_gateway_builder.rb +10 -21
  10. data/lib/jets/cfn/builders/base_child_builder.rb +49 -0
  11. data/lib/jets/cfn/{template_builders → builders}/controller_builder.rb +7 -7
  12. data/lib/jets/cfn/{template_builders → builders}/function_builder.rb +1 -2
  13. data/lib/jets/cfn/builders/interface.rb +128 -0
  14. data/lib/jets/cfn/{template_builders → builders}/job_builder.rb +2 -2
  15. data/lib/jets/cfn/builders/parent_builder.rb +84 -0
  16. data/lib/jets/cfn/{template_builders → builders}/rule_builder.rb +4 -5
  17. data/lib/jets/commands/base.rb +1 -1
  18. data/lib/jets/commands/build.rb +11 -15
  19. data/lib/jets/commands/delete.rb +12 -0
  20. data/lib/jets/commands/templates/skeleton/Gemfile.tt +1 -0
  21. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +1 -1
  22. data/lib/jets/commands/url.rb +10 -12
  23. data/lib/jets/controller/base.rb +2 -2
  24. data/lib/jets/core.rb +1 -1
  25. data/lib/jets/core_ext/kernel.rb +11 -1
  26. data/lib/jets/internal/app/controllers/jets/public_controller.rb +11 -8
  27. data/lib/jets/lambda/dsl.rb +1 -1
  28. data/lib/jets/lambda/task.rb +9 -1
  29. data/lib/jets/naming.rb +2 -2
  30. data/lib/jets/pascalize.rb +9 -1
  31. data/lib/jets/poly_fun/base_executor.rb +2 -2
  32. data/lib/jets/preheat.rb +2 -2
  33. data/lib/jets/rails_overrides/common_methods.rb +1 -1
  34. data/lib/jets/resource.rb +55 -5
  35. data/lib/jets/resource/api_gateway.rb +7 -0
  36. data/lib/jets/resource/{route → api_gateway}/cors.rb +11 -10
  37. data/lib/jets/resource/api_gateway/deployment.rb +75 -0
  38. data/lib/jets/resource/{route.rb → api_gateway/method.rb} +26 -22
  39. data/lib/jets/{cfn/template_mappers/gateway_resource_mapper.rb → resource/api_gateway/resource.rb} +41 -27
  40. data/lib/jets/resource/api_gateway/rest_api.rb +23 -0
  41. data/lib/jets/resource/base.rb +17 -0
  42. data/lib/jets/resource/child_stack.rb +5 -0
  43. data/lib/jets/resource/child_stack/api_deployment.rb +58 -0
  44. data/lib/jets/resource/child_stack/api_gateway.rb +29 -0
  45. data/lib/jets/resource/child_stack/app_class.rb +81 -0
  46. data/lib/jets/resource/function.rb +184 -0
  47. data/lib/jets/resource/iam.rb +8 -0
  48. data/lib/jets/resource/iam/application_role.rb +27 -0
  49. data/lib/jets/resource/iam/base_role_definition.rb +44 -0
  50. data/lib/jets/resource/iam/class_role.rb +25 -0
  51. data/lib/jets/resource/iam/function_role.rb +25 -0
  52. data/lib/jets/{cfn/template_builders/managed_iam_policy/base_policy.rb → resource/iam/managed_policy.rb} +6 -6
  53. data/lib/jets/resource/iam/policy_document.rb +43 -0
  54. data/lib/jets/resource/permission.rb +38 -21
  55. data/lib/jets/resource/replacer.rb +50 -17
  56. data/lib/jets/resource/s3.rb +17 -0
  57. data/lib/jets/route.rb +3 -1
  58. data/lib/jets/rule/dsl.rb +7 -1
  59. data/lib/jets/server/route_matcher.rb +2 -1
  60. data/lib/jets/version.rb +1 -1
  61. metadata +46 -52
  62. data/lib/jets/cfn/template_builders.rb +0 -25
  63. data/lib/jets/cfn/template_builders/api_gateway_deployment_builder.rb +0 -38
  64. data/lib/jets/cfn/template_builders/base_child_builder.rb +0 -72
  65. data/lib/jets/cfn/template_builders/function_properties.rb +0 -6
  66. data/lib/jets/cfn/template_builders/function_properties/base_builder.rb +0 -128
  67. data/lib/jets/cfn/template_builders/function_properties/node_builder.rb +0 -12
  68. data/lib/jets/cfn/template_builders/function_properties/python_builder.rb +0 -12
  69. data/lib/jets/cfn/template_builders/function_properties/ruby_builder.rb +0 -13
  70. data/lib/jets/cfn/template_builders/iam_policy.rb +0 -6
  71. data/lib/jets/cfn/template_builders/iam_policy/application_policy.rb +0 -19
  72. data/lib/jets/cfn/template_builders/iam_policy/base_policy.rb +0 -57
  73. data/lib/jets/cfn/template_builders/iam_policy/class_policy.rb +0 -20
  74. data/lib/jets/cfn/template_builders/iam_policy/function_policy.rb +0 -21
  75. data/lib/jets/cfn/template_builders/interface.rb +0 -97
  76. data/lib/jets/cfn/template_builders/managed_iam_policy.rb +0 -6
  77. data/lib/jets/cfn/template_builders/managed_iam_policy/application_policy.rb +0 -11
  78. data/lib/jets/cfn/template_builders/managed_iam_policy/class_policy.rb +0 -10
  79. data/lib/jets/cfn/template_builders/managed_iam_policy/function_policy.rb +0 -10
  80. data/lib/jets/cfn/template_builders/parent_builder.rb +0 -95
  81. data/lib/jets/cfn/template_builders/templates/minimal-stack.yml +0 -9
  82. data/lib/jets/cfn/template_mappers.rb +0 -22
  83. data/lib/jets/cfn/template_mappers/api_gateway_deployment_mapper.rb +0 -48
  84. data/lib/jets/cfn/template_mappers/api_gateway_mapper.rb +0 -4
  85. data/lib/jets/cfn/template_mappers/child_mapper.rb +0 -41
  86. data/lib/jets/cfn/template_mappers/controller_mapper.rb +0 -36
  87. data/lib/jets/cfn/template_mappers/function_mapper.rb +0 -4
  88. data/lib/jets/cfn/template_mappers/iam_policy.rb +0 -6
  89. data/lib/jets/cfn/template_mappers/iam_policy/application_policy_mapper.rb +0 -37
  90. data/lib/jets/cfn/template_mappers/iam_policy/base_policy_mapper.rb +0 -49
  91. data/lib/jets/cfn/template_mappers/iam_policy/class_policy_mapper.rb +0 -42
  92. data/lib/jets/cfn/template_mappers/iam_policy/function_policy_mapper.rb +0 -42
  93. data/lib/jets/cfn/template_mappers/job_mapper.rb +0 -4
  94. data/lib/jets/cfn/template_mappers/lambda_function_mapper.rb +0 -52
  95. data/lib/jets/cfn/template_mappers/rule_mapper.rb +0 -5
  96. data/lib/jets/resource/attributes.rb +0 -46
  97. data/lib/jets/resource/creator.rb +0 -17
  98. data/lib/jets/resource/replacer/base.rb +0 -98
  99. data/lib/jets/resource/replacer/config_rule.rb +0 -18
  100. data/lib/jets/resource/route/attributes.rb +0 -8
@@ -0,0 +1,75 @@
1
+ module Jets::Resource::ApiGateway
2
+ class Deployment < Jets::Resource::Base
3
+ def definition
4
+ {
5
+ deployment_logical_id => {
6
+ type: "AWS::ApiGateway::Deployment",
7
+ properties: {
8
+ description: "Version #{timestamp} deployed by jets",
9
+ rest_api_id: "!Ref RestApi",
10
+ stage_name: stage_name,
11
+ }
12
+ }
13
+ }
14
+ end
15
+
16
+ # value is Description
17
+ def parameters
18
+ {
19
+ "RestApi" => "RestApi",
20
+ }
21
+ end
22
+
23
+ # value is Value
24
+ def outputs
25
+ {
26
+ "RestApiUrl" => "!Sub 'https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/#{stage_name}/'",
27
+ }
28
+ end
29
+
30
+ def depends_on
31
+ expression = "#{Jets::Naming.template_path_prefix}-*_controller*"
32
+ controller_logical_ids = []
33
+ Dir.glob(expression).each do |path|
34
+ next unless File.file?(path)
35
+
36
+ regexp = Regexp.new(".*#{Jets.config.project_namespace}-")
37
+ controller_name = path.sub(regexp, '').sub('.yml', '')
38
+ # map the path to a camelized logical_id. Example:
39
+ # /tmp/jets/demo/templates/demo-dev-2-posts_controller.yml to
40
+ # PostsController
41
+ controller_logical_id = controller_name.underscore.camelize
42
+
43
+ controller_logical_ids << controller_logical_id
44
+ end
45
+ controller_logical_ids
46
+ end
47
+
48
+ # stage_name: dev, dev-1, dev-2, etc
49
+ def stage_name
50
+ self.class.stage_name
51
+ end
52
+
53
+ def self.stage_name
54
+ # Stage name only allows a-zA-Z0-9_
55
+ [Jets.config.short_env, Jets.config.env_extra].compact.join('_').gsub('-','_')
56
+ end
57
+
58
+ def timestamp
59
+ self.class.timestamp
60
+ end
61
+
62
+ @@timestamp = nil
63
+ def self.timestamp
64
+ @@timestamp ||= Time.now.strftime("%Y%m%d%H%M%S")
65
+ end
66
+
67
+ def deployment_logical_id
68
+ self.class.logical_id.underscore
69
+ end
70
+
71
+ def self.logical_id
72
+ "ApiDeployment#{timestamp}"
73
+ end
74
+ end
75
+ end
@@ -1,19 +1,20 @@
1
- # Converts a Jets::Route to a CloudFormation resource
2
- module Jets::Resource
3
- class Route
4
- autoload :Attributes, 'jets/resource/route/attributes'
5
- autoload :Cors, 'jets/resource/route/cors'
1
+ require "active_support/core_ext/object"
6
2
 
7
- extend Memoist
3
+ # Converts a Jets::Route to a CloudFormation Jets::Resource::ApiGateway::Method resource
4
+ module Jets::Resource::ApiGateway
5
+ class Method < Jets::Resource::Base
6
+ # also delegate permission for a method
7
+ delegate :permission,
8
+ to: :resource
8
9
 
9
10
  # route - Jets::Route
10
11
  def initialize(route)
11
12
  @route = route
12
13
  end
13
14
 
14
- def attributes
15
- attributes = {
16
- "#{method_logical_id}ApiMethod" => {
15
+ def definition
16
+ {
17
+ method_logical_id => {
17
18
  type: "AWS::ApiGateway::Method",
18
19
  properties: {
19
20
  resource_id: "!Ref #{resource_id}",
@@ -30,32 +31,35 @@ module Jets::Resource
30
31
  }
31
32
  }
32
33
  }
34
+ end
35
+
36
+ def method_logical_id
37
+ "{namespace}_api_method"
38
+ end
33
39
 
34
- definitions = attributes # to emphasize that its the same thing
40
+ def replacements
41
+ # mimic task to grab replacements, we want the namespace to be the lambda function's namespace
42
+ resources = [definition]
35
43
  task = Jets::Lambda::Task.new(@route.controller_name, @route.action_name,
36
- resources: definitions)
37
- Attributes.new(attributes, task)
44
+ resources: resources)
45
+ task.replacements
38
46
  end
39
- alias_method :resource, :attributes
40
- memoize :attributes
41
47
 
42
- private
43
- # Similar path_logical_id method in template_mappers/gateway_resource_mapper.rb
44
- # Example: PostsGet
45
- def method_logical_id
46
- path = camelized_path
47
- path + "#{@route.method.to_s.downcase.camelize}"
48
+ def cors
49
+ Cors.new(@route)
48
50
  end
51
+ memoize :cors
49
52
 
53
+ private
50
54
  def resource_id
51
55
  @route.path == '' ?
52
56
  "RootResourceId" :
53
- "#{resource_logical_id}ApiResource"
57
+ "#{resource_logical_id.camelize}ApiResource"
54
58
  end
55
59
 
56
60
  # Example: Posts
57
61
  def resource_logical_id
58
- camelized_path
62
+ camelized_path.underscore
59
63
  end
60
64
 
61
65
  def camelized_path
@@ -1,21 +1,54 @@
1
- class Jets::Cfn::TemplateMappers
2
- class GatewayResourceMapper
1
+ module Jets::Resource::ApiGateway
2
+ class Resource < Jets::Resource::Base
3
3
  def initialize(path)
4
4
  @path = path # Examples: "posts/:id/edit" or "posts"
5
5
  end
6
6
 
7
- # Returns: "ApiResourcePostsController"
8
- def logical_id
9
- homepage = @path == ''
10
- if homepage
7
+ def definition
8
+ {
9
+ resource_logical_id => {
10
+ type: "AWS::ApiGateway::Resource",
11
+ properties: {
12
+ parent_id: parent_id,
13
+ path_part: path_part,
14
+ rest_api_id: "!Ref RestApi",
15
+ }
16
+ }
17
+ }
18
+ end
19
+
20
+ def outputs
21
+ {
22
+ logical_id => "!Ref #{logical_id}",
23
+ }
24
+ end
25
+
26
+ def resource_logical_id
27
+ if @path == ''
11
28
  "RootResourceId"
12
29
  else
13
30
  "#{path_logical_id(@path)}ApiResource"
14
31
  end
15
32
  end
16
33
 
17
- def cors_logical_id
18
- "#{path_logical_id(@path)}CorsApiResource"
34
+ # For parameter description
35
+ def desc
36
+ path.empty? ? 'Homepage route: /' : "Route for: /#{path}"
37
+ end
38
+
39
+ def parent_id
40
+ if @path.include?('/') # posts/:id or posts/:id/edit
41
+ parent_path = @path.split('/')[0..-2].join('/')
42
+ parent_logical_id = path_logical_id(parent_path)
43
+ "!Ref #{parent_logical_id}ApiResource"
44
+ else
45
+ "!GetAtt RestApi.RootResourceId"
46
+ end
47
+ end
48
+
49
+ def path_part
50
+ last_part = path.split('/').last
51
+ last_part.split('/').map {|s| transform_capture(s) }.join('/') if last_part
19
52
  end
20
53
 
21
54
  # Modify the path to conform to API Gateway capture expressions
@@ -23,10 +56,6 @@ class Jets::Cfn::TemplateMappers
23
56
  @path.split('/').map {|s| transform_capture(s) }.join('/')
24
57
  end
25
58
 
26
- def desc
27
- path.empty? ? 'Homepage route: /' : "Route for: /#{path}"
28
- end
29
-
30
59
  def transform_capture(text)
31
60
  if text.starts_with?(':')
32
61
  text = text.sub(':','')
@@ -39,21 +68,6 @@ class Jets::Cfn::TemplateMappers
39
68
  text
40
69
  end
41
70
 
42
- def parent_id
43
- if @path.include?('/') # posts/:id or posts/:id/edit
44
- parent_path = @path.split('/')[0..-2].join('/')
45
- parent_logical_id = path_logical_id(parent_path)
46
- "!Ref #{parent_logical_id}ApiResource"
47
- else
48
- "!GetAtt RestApi.RootResourceId"
49
- end
50
- end
51
-
52
- def path_part
53
- last_part = path.split('/').last
54
- last_part.split('/').map {|s| transform_capture(s) }.join('/')
55
- end
56
-
57
71
  private
58
72
  # Similar path_logical_id method in resource/route.rb
59
73
  def path_logical_id(path)
@@ -0,0 +1,23 @@
1
+ module Jets::Resource::ApiGateway
2
+ class RestApi < Jets::Resource::Base
3
+ def definition
4
+ {
5
+ rest_api: {
6
+ type: "AWS::ApiGateway::RestApi",
7
+ properties: {
8
+ name: Jets::Naming.gateway_api_name,
9
+ # binary_media_types: ['*/*'], # TODO: comment out, breaking form post
10
+ }
11
+ }
12
+ }
13
+ end
14
+
15
+ def outputs
16
+ {
17
+ "RestApi" => "!Ref RestApi",
18
+ "Region" => "!Ref AWS::Region",
19
+ "RootResourceId" => "!GetAtt RestApi.RootResourceId",
20
+ }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ class Jets::Resource
2
+ class Base
3
+ extend Memoist
4
+ delegate :logical_id, :type, :properties, :attributes, :parameters, :outputs,
5
+ to: :resource
6
+
7
+ # Usually overridden
8
+ def resource
9
+ Jets::Resource.new(definition, replacements)
10
+ end
11
+ memoize :resource
12
+
13
+ def replacements
14
+ @replacements || {}
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Jets::Resource::ChildStack
2
+ autoload :AppClass, 'jets/resource/child_stack/app_class'
3
+ autoload :ApiGateway, 'jets/resource/child_stack/api_gateway'
4
+ autoload :ApiDeployment, 'jets/resource/child_stack/api_deployment'
5
+ end
@@ -0,0 +1,58 @@
1
+ module Jets::Resource::ChildStack
2
+ class ApiDeployment < Jets::Resource::Base
3
+ def initialize(s3_bucket)
4
+ @s3_bucket = s3_bucket
5
+ end
6
+
7
+ def definition
8
+ {
9
+ deployment_id => {
10
+ type: "AWS::CloudFormation::Stack",
11
+ properties: {
12
+ template_url: template_url,
13
+ parameters: parameters,
14
+ },
15
+ depends_on: depends_on,
16
+ }
17
+ }
18
+ end
19
+
20
+ def parameters
21
+ {
22
+ RestApi: "!GetAtt ApiGateway.Outputs.RestApi",
23
+ }
24
+ end
25
+
26
+ def depends_on
27
+ expression = "#{Jets::Naming.template_path_prefix}-*_controller*"
28
+ controller_logical_ids = []
29
+ Dir.glob(expression).each do |path|
30
+ next unless File.file?(path)
31
+
32
+ # map the path to a camelized logical_id. Example:
33
+ # /tmp/jets/demo/templates/demo-dev-2-posts_controller.yml to
34
+ # PostsController
35
+ regexp = Regexp.new(".*#{Jets.config.project_namespace}-")
36
+ controller_name = path.sub(regexp, '').sub('.yml', '')
37
+ controller_logical_id = controller_name.underscore.camelize
38
+ controller_logical_ids << controller_logical_id
39
+ end
40
+ controller_logical_ids
41
+ end
42
+
43
+ def outputs
44
+ {
45
+ logical_id => "!Ref #{logical_id}",
46
+ }
47
+ end
48
+
49
+ def deployment_id
50
+ Jets::Resource::ApiGateway::Deployment.logical_id
51
+ end
52
+
53
+ def template_url
54
+ path = File.basename("#{Jets.config.project_namespace}-api-deployment.yml")
55
+ "https://s3.amazonaws.com/#{@s3_bucket}/jets/cfn-templates/#{path}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,29 @@
1
+ module Jets::Resource::ChildStack
2
+ class ApiGateway < Jets::Resource::Base
3
+ def initialize(s3_bucket)
4
+ @s3_bucket = s3_bucket
5
+ end
6
+
7
+ def definition
8
+ {
9
+ api_gateway: {
10
+ type: "AWS::CloudFormation::Stack",
11
+ properties: {
12
+ template_url: template_url,
13
+ }
14
+ }
15
+ }
16
+ end
17
+
18
+ def outputs
19
+ {
20
+ logical_id => "!Ref #{logical_id}",
21
+ }
22
+ end
23
+
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}"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,81 @@
1
+ module Jets::Resource::ChildStack
2
+ class AppClass < Jets::Resource::Base
3
+ def initialize(path, s3_bucket)
4
+ @path = path
5
+ @s3_bucket = s3_bucket
6
+ end
7
+
8
+ def definition
9
+ logical_id = app_logical_id
10
+ {
11
+ logical_id => {
12
+ type: "AWS::CloudFormation::Stack",
13
+ properties: {
14
+ template_url: template_url,
15
+ parameters: parameters,
16
+ }
17
+ }
18
+ }
19
+ end
20
+
21
+ def parameters
22
+ common = {
23
+ IamRole: "!GetAtt IamRole.Arn",
24
+ S3Bucket: "!Ref S3Bucket",
25
+ }
26
+ common.merge!(controller_params) if controller?
27
+ common
28
+ end
29
+
30
+ def controller_params
31
+ return {} if Jets::Router.routes.empty?
32
+
33
+ params = {
34
+ RestApi: "!GetAtt ApiGateway.Outputs.RestApi",
35
+ }
36
+ scoped_routes.each do |route|
37
+ resource = Jets::Resource::ApiGateway::Resource.new(route.path)
38
+ params[resource.logical_id] = "!GetAtt ApiGateway.Outputs.#{resource.logical_id}"
39
+ end
40
+ params
41
+ end
42
+
43
+ def controller?
44
+ @path.include?('_controller.yml')
45
+ end
46
+
47
+ def scoped_routes
48
+ @routes ||= Jets::Router.routes.select do |route|
49
+ route.controller_name == current_app_class
50
+ end
51
+ end
52
+
53
+ def current_app_class
54
+ templates_prefix = "#{Jets::Naming.template_path_prefix}-"
55
+ @path.sub(templates_prefix, '')
56
+ .sub(/\.yml$/,'')
57
+ .gsub('-','/')
58
+ .classify
59
+ end
60
+
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
+ # map the path to a camelized logical_id. Example:
69
+ # /tmp/jets/demo/templates/demo-dev-2-posts_controller.yml to
70
+ # PostsController
71
+ def app_logical_id
72
+ regexp = Regexp.new(".*#{Jets.config.project_namespace}-")
73
+ controller_name = @path.sub(regexp, '').sub('.yml', '')
74
+ controller_name.underscore.camelize
75
+ end
76
+
77
+ def template_url
78
+ "https://s3.amazonaws.com/#{@s3_bucket}/jets/cfn-templates/#{File.basename(@path)}"
79
+ end
80
+ end
81
+ end