jets 1.5.9 → 1.5.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +3 -3
- data/lib/jets/commands/new.rb +1 -0
- data/lib/jets/resource/api_gateway/base_path/role.rb +1 -1
- data/lib/jets/resource/api_gateway/rest_api/logical_id.rb +0 -1
- data/lib/jets/resource/api_gateway/rest_api/routes/change.rb +6 -108
- data/lib/jets/resource/api_gateway/rest_api/routes/change/base.rb +100 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change/to.rb +29 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change/variable.rb +39 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/collision.rb +15 -13
- data/lib/jets/router.rb +3 -2
- data/lib/jets/version.rb +1 -1
- metadata +5 -3
- data/lib/jets/resource/api_gateway/rest_api/routes/base.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39b6cde7b66e43e4c253e0f055952680298287d9e7c534c4a465ca075b3dfb62
|
4
|
+
data.tar.gz: d3312104416979ca67bd31cebd3a7c2ba604185349c2c368de438d50a68914ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1b670d6b6a2c0189fd608d4a7ba61a02206a4ddf78d2c8eda2c4f06d8c4c1beddb2588b417211e697ea0b24f8c426975c9ab08819a56fc3da41f6c959fb272ca
|
7
|
+
data.tar.gz: c84383ea55a03f9b0576fb5ea7c4a895a9e5ae818bd79df008a9e7f621f93ce2d5e4e189d7f4aa9a9a2c0fef12ae7a668747308b263785de0b8d0c46da8330f7
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
This project *loosely tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
|
5
5
|
|
6
|
+
## [1.5.10]
|
7
|
+
- #157 Improve Route Change Detection: Path Variables
|
8
|
+
|
6
9
|
## [1.5.9]
|
7
10
|
- #154 from tongueroo/variable-collision raise error on multiple sibling variable paths collision
|
8
11
|
- #156 from konnected-io/master: don't prewarm jobs, only prewarm controllers
|
data/Gemfile.lock
CHANGED
@@ -11,7 +11,7 @@ GIT
|
|
11
11
|
PATH
|
12
12
|
remote: .
|
13
13
|
specs:
|
14
|
-
jets (1.5.
|
14
|
+
jets (1.5.10)
|
15
15
|
activerecord (~> 5.2.1)
|
16
16
|
activesupport (~> 5.2.1)
|
17
17
|
aws-sdk-apigateway
|
@@ -66,7 +66,7 @@ GEM
|
|
66
66
|
tzinfo (~> 1.1)
|
67
67
|
arel (9.0.0)
|
68
68
|
aws-eventstream (1.0.1)
|
69
|
-
aws-partitions (1.
|
69
|
+
aws-partitions (1.133.0)
|
70
70
|
aws-sdk-apigateway (1.23.0)
|
71
71
|
aws-sdk-core (~> 3, >= 3.39.0)
|
72
72
|
aws-sigv4 (~> 1.0)
|
@@ -87,7 +87,7 @@ GEM
|
|
87
87
|
aws-sdk-kms (1.13.0)
|
88
88
|
aws-sdk-core (~> 3, >= 3.39.0)
|
89
89
|
aws-sigv4 (~> 1.0)
|
90
|
-
aws-sdk-lambda (1.
|
90
|
+
aws-sdk-lambda (1.17.0)
|
91
91
|
aws-sdk-core (~> 3, >= 3.39.0)
|
92
92
|
aws-sigv4 (~> 1.0)
|
93
93
|
aws-sdk-s3 (1.30.1)
|
data/lib/jets/commands/new.rb
CHANGED
@@ -55,7 +55,7 @@ module Jets::Resource::ApiGateway::BasePath
|
|
55
55
|
# Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
|
56
56
|
def rest_api_id
|
57
57
|
stack_name = Jets::Naming.parent_stack_name
|
58
|
-
return
|
58
|
+
return "RestApi" unless stack_exists?(stack_name)
|
59
59
|
|
60
60
|
stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
|
61
61
|
|
@@ -1,114 +1,12 @@
|
|
1
1
|
# Detects route changes
|
2
2
|
class Jets::Resource::ApiGateway::RestApi::Routes
|
3
|
-
class Change
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
if new_route && new_route.to != deployed_route.to
|
8
|
-
# change in already deployed route has been detected, requires bluegreen deploy
|
9
|
-
return true
|
10
|
-
end
|
11
|
-
end
|
12
|
-
false # Reaching here means no routes have been changed in a way that requires a bluegreen deploy
|
13
|
-
end
|
14
|
-
|
15
|
-
# Build up deployed routes from the existing CloudFormation resources.
|
16
|
-
def deployed_routes
|
17
|
-
routes = []
|
18
|
-
|
19
|
-
resources, position = [], true
|
20
|
-
while position
|
21
|
-
position = nil if position == true # start of loop
|
22
|
-
resp = apigateway.get_resources(
|
23
|
-
rest_api_id: rest_api_id,
|
24
|
-
position: position,
|
25
|
-
)
|
26
|
-
resources += resp.items
|
27
|
-
position = resp.position
|
28
|
-
end
|
29
|
-
|
30
|
-
resources.each do |resource|
|
31
|
-
resource_methods = resource.resource_methods
|
32
|
-
next if resource_methods.nil?
|
33
|
-
|
34
|
-
resource_methods.each do |http_verb, resource_method|
|
35
|
-
# puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
|
36
|
-
# puts to(resource.id, http_verb)
|
3
|
+
class Change
|
4
|
+
autoload :Base, 'jets/resource/api_gateway/rest_api/routes/change/base'
|
5
|
+
autoload :To, 'jets/resource/api_gateway/rest_api/routes/change/to'
|
6
|
+
autoload :Variable, 'jets/resource/api_gateway/rest_api/routes/change/variable'
|
37
7
|
|
38
|
-
|
39
|
-
|
40
|
-
next if http_verb == "OPTIONS"
|
41
|
-
|
42
|
-
path = recreate_path(resource.path)
|
43
|
-
method = http_verb.downcase.to_sym
|
44
|
-
to = to(resource.id, http_verb)
|
45
|
-
route = Jets::Route.new(path: path, method: method, to: to)
|
46
|
-
routes << route
|
47
|
-
end
|
48
|
-
end
|
49
|
-
routes
|
50
|
-
end
|
51
|
-
memoize :deployed_routes
|
52
|
-
|
53
|
-
# Find a route that has the same path and method. This is a comparable route
|
54
|
-
# Then we will compare the to or controller action to see if an already
|
55
|
-
# deployed route has been changed.
|
56
|
-
def find_comparable_route(deployed_route)
|
57
|
-
new_routes.find do |new_route|
|
58
|
-
new_route.path == deployed_route.path &&
|
59
|
-
new_route.method == deployed_route.method
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def recreate_path(path)
|
64
|
-
path = path.gsub(%r{^/},'')
|
65
|
-
path = path.sub(/{(.*)\+}/, '*\1')
|
66
|
-
path.sub(/{(.*)}/, ':\1')
|
67
|
-
end
|
68
|
-
|
69
|
-
def to(resource_id, http_method)
|
70
|
-
uri = method_uri(resource_id, http_method)
|
71
|
-
recreate_to(uri) unless uri.nil?
|
72
|
-
end
|
73
|
-
|
74
|
-
def method_uri(resource_id, http_method)
|
75
|
-
resp = apigateway.get_method(
|
76
|
-
rest_api_id: rest_api_id,
|
77
|
-
resource_id: resource_id,
|
78
|
-
http_method: http_method
|
79
|
-
)
|
80
|
-
resp.method_integration.uri
|
81
|
-
end
|
82
|
-
|
83
|
-
# Parses method uri and recreates a Route to argument.
|
84
|
-
# So:
|
85
|
-
# "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:112233445566:function:demo-test-posts_controller-new/invocations"
|
86
|
-
# Returns:
|
87
|
-
# posts#new
|
88
|
-
def recreate_to(method_uri)
|
89
|
-
md = method_uri.match(/function:(.*)\//)
|
90
|
-
function_name = md[1] # IE: demo-dev-posts_controller-new
|
91
|
-
controller_action = function_name.sub("#{Jets.project_namespace}-", '')
|
92
|
-
md = controller_action.match(/(.*)_controller-(.*)/)
|
93
|
-
controller = md[1]
|
94
|
-
controller = controller.gsub('-','/')
|
95
|
-
action = md[2]
|
96
|
-
"#{controller}##{action}" # IE: posts#new
|
97
|
-
end
|
98
|
-
|
99
|
-
# Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
|
100
|
-
def rest_api_id
|
101
|
-
stack_name = Jets::Naming.parent_stack_name
|
102
|
-
return default unless stack_exists?(stack_name)
|
103
|
-
|
104
|
-
stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
|
105
|
-
|
106
|
-
api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")
|
107
|
-
|
108
|
-
# resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
|
109
|
-
stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
|
110
|
-
lookup(stack[:outputs], "RestApi") # rest_api_id
|
8
|
+
def changed?
|
9
|
+
To.changed? || Variable.changed? || ENV['JETS_REPLACE_API']
|
111
10
|
end
|
112
|
-
memoize :rest_api_id
|
113
11
|
end
|
114
12
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Jets::Resource::ApiGateway::RestApi::Routes::Change
|
2
|
+
class Base
|
3
|
+
extend Memoist
|
4
|
+
include Jets::AwsServices
|
5
|
+
|
6
|
+
# Build up deployed routes from the existing CloudFormation resources.
|
7
|
+
def deployed_routes
|
8
|
+
routes = []
|
9
|
+
|
10
|
+
resources, position = [], true
|
11
|
+
while position
|
12
|
+
position = nil if position == true # start of loop
|
13
|
+
resp = apigateway.get_resources(
|
14
|
+
rest_api_id: rest_api_id,
|
15
|
+
position: position,
|
16
|
+
)
|
17
|
+
resources += resp.items
|
18
|
+
position = resp.position
|
19
|
+
end
|
20
|
+
|
21
|
+
resources.each do |resource|
|
22
|
+
resource_methods = resource.resource_methods
|
23
|
+
next if resource_methods.nil?
|
24
|
+
|
25
|
+
resource_methods.each do |http_verb, resource_method|
|
26
|
+
# puts "#{http_verb} #{resource.path} | resource.id #{resource.id}"
|
27
|
+
# puts to(resource.id, http_verb)
|
28
|
+
|
29
|
+
# Test changing config.cors and CloudFormation does an in-place update
|
30
|
+
# on the resource. So no need to do bluegreen deployments for OPTIONS.
|
31
|
+
next if http_verb == "OPTIONS"
|
32
|
+
|
33
|
+
path = recreate_path(resource.path)
|
34
|
+
method = http_verb.downcase.to_sym
|
35
|
+
to = to(resource.id, http_verb)
|
36
|
+
route = Jets::Route.new(path: path, method: method, to: to)
|
37
|
+
routes << route
|
38
|
+
end
|
39
|
+
end
|
40
|
+
routes
|
41
|
+
end
|
42
|
+
memoize :deployed_routes
|
43
|
+
|
44
|
+
def recreate_path(path)
|
45
|
+
path = path.gsub(%r{^/},'')
|
46
|
+
path = path.sub(/{(.*)\+}/, '*\1')
|
47
|
+
path.sub(/{(.*)}/, ':\1')
|
48
|
+
end
|
49
|
+
|
50
|
+
def to(resource_id, http_method)
|
51
|
+
uri = method_uri(resource_id, http_method)
|
52
|
+
recreate_to(uri) unless uri.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_uri(resource_id, http_method)
|
56
|
+
resp = apigateway.get_method(
|
57
|
+
rest_api_id: rest_api_id,
|
58
|
+
resource_id: resource_id,
|
59
|
+
http_method: http_method
|
60
|
+
)
|
61
|
+
resp.method_integration.uri
|
62
|
+
end
|
63
|
+
|
64
|
+
# Parses method uri and recreates a Route to argument.
|
65
|
+
# So:
|
66
|
+
# "arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:112233445566:function:demo-test-posts_controller-new/invocations"
|
67
|
+
# Returns:
|
68
|
+
# posts#new
|
69
|
+
def recreate_to(method_uri)
|
70
|
+
md = method_uri.match(/function:(.*)\//)
|
71
|
+
function_name = md[1] # IE: demo-dev-posts_controller-new
|
72
|
+
controller_action = function_name.sub("#{Jets.project_namespace}-", '')
|
73
|
+
md = controller_action.match(/(.*)_controller-(.*)/)
|
74
|
+
controller = md[1]
|
75
|
+
controller = controller.gsub('-','/')
|
76
|
+
action = md[2]
|
77
|
+
"#{controller}##{action}" # IE: posts#new
|
78
|
+
end
|
79
|
+
|
80
|
+
# Duplicated in rest_api/change_detection.rb, base_path/role.rb, rest_api/routes.rb
|
81
|
+
def rest_api_id
|
82
|
+
stack_name = Jets::Naming.parent_stack_name
|
83
|
+
return "RestApi" unless stack_exists?(stack_name)
|
84
|
+
|
85
|
+
stack = cfn.describe_stacks(stack_name: stack_name).stacks.first
|
86
|
+
|
87
|
+
api_gateway_stack_arn = lookup(stack[:outputs], "ApiGateway")
|
88
|
+
|
89
|
+
# resources = cfn.describe_stack_resources(stack_name: api_gateway_stack_arn).stack_resources
|
90
|
+
stack = cfn.describe_stacks(stack_name: api_gateway_stack_arn).stacks.first
|
91
|
+
lookup(stack[:outputs], "RestApi") # rest_api_id
|
92
|
+
end
|
93
|
+
memoize :rest_api_id
|
94
|
+
|
95
|
+
def new_routes
|
96
|
+
Jets::Router.routes
|
97
|
+
end
|
98
|
+
memoize :new_routes
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Detects route to changes
|
2
|
+
class Jets::Resource::ApiGateway::RestApi::Routes::Change
|
3
|
+
class To < Base
|
4
|
+
def self.changed?
|
5
|
+
new.changed?
|
6
|
+
end
|
7
|
+
|
8
|
+
def changed?
|
9
|
+
deployed_routes.each do |deployed_route|
|
10
|
+
new_route = find_comparable_route(deployed_route)
|
11
|
+
if new_route && new_route.to != deployed_route.to
|
12
|
+
# change in already deployed route has been detected, requires bluegreen deploy
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
false # Reaching here means no routes have been changed in a way that requires a bluegreen deploy
|
17
|
+
end
|
18
|
+
|
19
|
+
# Find a route that has the same path and method. This is a comparable route
|
20
|
+
# Then we will compare the to or controller action to see if an already
|
21
|
+
# deployed route has been changed.
|
22
|
+
def find_comparable_route(deployed_route)
|
23
|
+
new_routes.find do |new_route|
|
24
|
+
new_route.path == deployed_route.path &&
|
25
|
+
new_route.method == deployed_route.method
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Detects route variable changes
|
2
|
+
class Jets::Resource::ApiGateway::RestApi::Routes::Change
|
3
|
+
class Variable < Base
|
4
|
+
def self.changed?
|
5
|
+
new.changed?
|
6
|
+
end
|
7
|
+
|
8
|
+
def changed?
|
9
|
+
changed = false
|
10
|
+
deployed_routes.each do |deployed_route|
|
11
|
+
parent = collision.variable_parent(deployed_route.path)
|
12
|
+
parent_variables = collision.parent_variables(parent, [deployed_route.path])
|
13
|
+
new_parent_variables = collision.parent_variables(parent, new_paths)
|
14
|
+
|
15
|
+
changed = parent_variables.size > 0 && new_parent_variables.size > 0 &&
|
16
|
+
parent_variables != new_parent_variables
|
17
|
+
break if changed
|
18
|
+
end
|
19
|
+
changed
|
20
|
+
end
|
21
|
+
|
22
|
+
# Only consider paths with variables
|
23
|
+
def new_paths
|
24
|
+
new_routes.map(&:path).select {|p| p.include?(':')}.uniq
|
25
|
+
end
|
26
|
+
|
27
|
+
# Only consider deployed routes with variables
|
28
|
+
def deployed_routes
|
29
|
+
deployed_routes = super
|
30
|
+
deployed_routes.select do |route|
|
31
|
+
route.path.include?(':')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def collision
|
36
|
+
@collision ||= Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
# Detects path variable collisions
|
2
2
|
class Jets::Resource::ApiGateway::RestApi::Routes
|
3
|
-
class Collision
|
3
|
+
class Collision
|
4
4
|
autoload :VariableException, 'jets/resource/api_gateway/rest_api/routes/collision/variable_exception'
|
5
5
|
|
6
6
|
attr_reader :collisions
|
7
|
-
def initialize
|
8
|
-
@routes = routes
|
7
|
+
def initialize
|
9
8
|
@collisions = []
|
10
9
|
end
|
11
10
|
|
12
|
-
def collision?
|
13
|
-
paths = paths_with_variables(
|
11
|
+
def collision?(paths)
|
12
|
+
paths = paths_with_variables(paths)
|
14
13
|
parents = variable_parents(paths)
|
15
14
|
|
16
15
|
collide = false
|
@@ -21,7 +20,11 @@ class Jets::Resource::ApiGateway::RestApi::Routes
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def exception
|
24
|
-
collision_message
|
23
|
+
VariableException.new(collision_message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def collision_message
|
27
|
+
<<~EOL
|
25
28
|
There are routes with sibling variables under the same parent that collide.
|
26
29
|
|
27
30
|
Collisions:
|
@@ -34,7 +37,6 @@ class Jets::Resource::ApiGateway::RestApi::Routes
|
|
34
37
|
Please check your `config/routes.rb` and remove the colliding routes.
|
35
38
|
More info: http://rubyonjets.com/docs/considerations-api-gateway/
|
36
39
|
EOL
|
37
|
-
VariableException.new(collision_message)
|
38
40
|
end
|
39
41
|
|
40
42
|
def variable_collision_exists?(parent, paths)
|
@@ -88,13 +90,9 @@ class Jets::Resource::ApiGateway::RestApi::Routes
|
|
88
90
|
parents.uniq.sort
|
89
91
|
end
|
90
92
|
|
91
|
-
def paths_with_variables(paths)
|
92
|
-
paths.select { |p| p.include?(':') }.uniq
|
93
|
-
end
|
94
|
-
|
95
93
|
# Strips the path down until only the leaf node part is a variable
|
96
94
|
# Example: users/:user_id/posts/:post_id/edit
|
97
|
-
# Returns: users/:user_id/posts
|
95
|
+
# Returns: users/:user_id/posts
|
98
96
|
def variable_parent(path)
|
99
97
|
path = variable_leaf(path)
|
100
98
|
# drop last variable to leave behind the parent
|
@@ -105,7 +103,7 @@ class Jets::Resource::ApiGateway::RestApi::Routes
|
|
105
103
|
# Example: users/:user_id/posts/:post_id/edit
|
106
104
|
# Returns: users/:user_id/posts
|
107
105
|
def variable_leaf(path)
|
108
|
-
return unless path.include?(':')
|
106
|
+
return '' unless path.include?(':')
|
109
107
|
|
110
108
|
parts = path.split('/')
|
111
109
|
is_variable = parts.last.include?(':')
|
@@ -115,5 +113,9 @@ class Jets::Resource::ApiGateway::RestApi::Routes
|
|
115
113
|
end
|
116
114
|
parts[0..-1].join('/') # parent
|
117
115
|
end
|
116
|
+
|
117
|
+
def paths_with_variables(paths)
|
118
|
+
paths.select { |p| p.include?(':') }.uniq
|
119
|
+
end
|
118
120
|
end
|
119
121
|
end
|
data/lib/jets/router.rb
CHANGED
@@ -16,8 +16,9 @@ module Jets
|
|
16
16
|
|
17
17
|
# Validate routes that deployable
|
18
18
|
def check_collision!
|
19
|
-
|
20
|
-
|
19
|
+
paths = self.routes.map(&:path)
|
20
|
+
collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
|
21
|
+
collide = collision.collision?(paths)
|
21
22
|
raise collision.exception if collide
|
22
23
|
end
|
23
24
|
|
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: 1.5.
|
4
|
+
version: 1.5.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -704,8 +704,10 @@ files:
|
|
704
704
|
- lib/jets/resource/api_gateway/rest_api/change_detection.rb
|
705
705
|
- lib/jets/resource/api_gateway/rest_api/logical_id.rb
|
706
706
|
- lib/jets/resource/api_gateway/rest_api/routes.rb
|
707
|
-
- lib/jets/resource/api_gateway/rest_api/routes/base.rb
|
708
707
|
- lib/jets/resource/api_gateway/rest_api/routes/change.rb
|
708
|
+
- lib/jets/resource/api_gateway/rest_api/routes/change/base.rb
|
709
|
+
- lib/jets/resource/api_gateway/rest_api/routes/change/to.rb
|
710
|
+
- lib/jets/resource/api_gateway/rest_api/routes/change/variable.rb
|
709
711
|
- lib/jets/resource/api_gateway/rest_api/routes/collision.rb
|
710
712
|
- lib/jets/resource/api_gateway/rest_api/routes/collision/variable_exception.rb
|
711
713
|
- lib/jets/resource/associated.rb
|