jets 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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