swaggerless 0.1.1 → 0.1.2
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/lib/swaggerless/deployer.rb +112 -39
- data/lib/swaggerless/version.rb +1 -1
- data/lib/tasks/swaggerless.rake +43 -38
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d694d07f97c1af61e3c9ae6711123dbf7256d1e4
|
4
|
+
data.tar.gz: 9d5618bdf56253b8c8924673ebf9431ede719e8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f04f394a5a902379f3ed2acf25bbb3d1b6edd8da3dcbabacb9f8f1cb3e8e8fd785457d81d51c6b8138ff6bbc0f111033c2726bdc662f64164bf541388a19d752
|
7
|
+
data.tar.gz: 3b76780b95ee2f581b21a4be4953dcea1e8f2ce61724ea32739015f0673e58e7e828942c0715c046c52c51b9b08c5f839d77169bc3f50fcb46d5c1087a5e73e0
|
data/lib/swaggerless/deployer.rb
CHANGED
@@ -8,8 +8,9 @@ module Swaggerless
|
|
8
8
|
@env = env
|
9
9
|
@region = region
|
10
10
|
@account = account
|
11
|
-
@
|
12
|
-
@
|
11
|
+
@api_gateway_client = Aws::APIGateway::Client.new(region: @region)
|
12
|
+
@output_path = 'output'
|
13
|
+
@verbose = false;
|
13
14
|
@function_alias = get_current_package_alias
|
14
15
|
end
|
15
16
|
|
@@ -21,40 +22,59 @@ module Swaggerless
|
|
21
22
|
return swagger["info"]["title"].gsub(/\s+/, '_')
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
+
EXT_LAMBDA_NAME = 'x-amazon-lambda-name'
|
26
|
+
EXT_LAMBDA_HANDLER = 'x-amazon-lambda-handler'
|
27
|
+
EXT_LAMBDA_TIMEOUT = 'x-amazon-lambda-timeout'
|
28
|
+
EXT_LAMBDA_RUNTIME = 'x-amazon-lambda-runtime'
|
29
|
+
|
30
|
+
AMZ_APIGATEWAY_AUTHORIZER = 'x-amazon-apigateway-authorizer'
|
31
|
+
|
32
|
+
SWGR_OPERATION_ID = 'operationId'
|
33
|
+
SWGR_SUMMARY = 'summary'
|
34
|
+
|
35
|
+
def deploy_authoirizers_and_update_authorizers_uri(lambda_role_arn, swagger)
|
25
36
|
swagger["securityDefinitions"].each do |securityDefinitionName, securityDefinition|
|
26
|
-
if securityDefinition[
|
27
|
-
authorizer = securityDefinition[
|
28
|
-
securityDefinition[
|
29
|
-
|
37
|
+
if securityDefinition[AMZ_APIGATEWAY_AUTHORIZER] != nil then
|
38
|
+
authorizer = securityDefinition[EXT_LAMBDA_NAME]
|
39
|
+
if securityDefinition[EXT_LAMBDA_NAME] then
|
40
|
+
securityDefinition[AMZ_APIGATEWAY_AUTHORIZER]["authorizerUri"] = deploy_lambda(lambda_role_arn, securityDefinition[EXT_LAMBDA_NAME],
|
41
|
+
"Authorizer for #{swagger["info"]["title"]}", securityDefinition[EXT_LAMBDA_RUNTIME], securityDefinition[EXT_LAMBDA_HANDLER],
|
42
|
+
securityDefinition[EXT_LAMBDA_TIMEOUT])
|
43
|
+
else
|
44
|
+
securityDefinition[AMZ_APIGATEWAY_AUTHORIZER]["authorizerUri"] = "arn:aws:apigateway:#{@region}:lambda:path/2015-03-31/functions/arn:aws:lambda:#{@region}:#{@account}:function:#{authorizer}/invocations"
|
45
|
+
end
|
46
|
+
lambda_client = Aws::Lambda::Client.new(region: @region)
|
30
47
|
policy_exists = false
|
31
48
|
begin
|
32
|
-
existing_policies =
|
49
|
+
existing_policies = lambda_client.get_policy(function_name: authorizer).data
|
33
50
|
existing_policy = JSON.parse(existing_policies.policy)
|
34
51
|
policy_exists = existing_policy['Statement'].select { |s| s['Sid'] == "API_2_#{authorizer}" }.any?
|
35
52
|
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
36
53
|
policy_exists = false
|
37
54
|
end
|
38
55
|
unless policy_exists
|
39
|
-
|
40
|
-
|
56
|
+
lambda_client.add_permission({function_name: "arn:aws:lambda:#{@region}:#{@account}:function:#{authorizer}",
|
57
|
+
statement_id: "API_2_#{authorizer}", action: "lambda:*", principal: 'apigateway.amazonaws.com'})
|
41
58
|
end
|
42
59
|
end
|
43
60
|
end
|
44
61
|
end
|
45
62
|
|
46
|
-
def
|
47
|
-
|
63
|
+
def deploy_lambdas_and_update_uris(lambda_role_arn, swagger)
|
64
|
+
lambdas_configs = get_lambda_map(swagger)
|
65
|
+
deployed_operations = Hash.new
|
48
66
|
swagger["paths"].each do |path, path_config|
|
49
67
|
path_config.each do |method, method_config|
|
50
|
-
if method_config[
|
51
|
-
if
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
method_config['operationId'], method_config['x-amazon-lambda-timeout'] || 5)
|
68
|
+
if method_config[SWGR_OPERATION_ID] or method_config[EXT_LAMBDA_HANDLER] then
|
69
|
+
if deployed_operations[method_config[EXT_LAMBDA_NAME]] == nil
|
70
|
+
config = lambdas_configs[method_config[EXT_LAMBDA_NAME]]
|
71
|
+
deployed_operations[method_config[EXT_LAMBDA_NAME]] = deploy_lambda(lambda_role_arn, method_config[EXT_LAMBDA_NAME], config[:description],
|
72
|
+
config[:runtime], config[:handler], config[:timeout])
|
56
73
|
end
|
57
|
-
|
74
|
+
puts "Updating swagger with integration uri for #{method} #{path}: #{deployed_operations[method_config[EXT_LAMBDA_NAME]]}" unless not @verbose
|
75
|
+
method_config['x-amazon-apigateway-integration']['uri'] = deployed_operations[method_config[EXT_LAMBDA_NAME]]
|
76
|
+
elsif method_config[EXT_LAMBDA_NAME] then
|
77
|
+
method_config['x-amazon-apigateway-integration']['uri'] = "arn:aws:apigateway:#{@region}:lambda:path/2015-03-31/functions/arn:aws:lambda:#{@region}:#{@account}:function:#{method_config[EXT_LAMBDA_NAME]}/invocations"
|
58
78
|
end
|
59
79
|
end
|
60
80
|
end
|
@@ -62,46 +82,48 @@ module Swaggerless
|
|
62
82
|
|
63
83
|
def deploy_lambda(lambda_role_arn, function_name, summary, runtime, handler, timeout)
|
64
84
|
puts "Deploying #{function_name}"
|
65
|
-
|
85
|
+
runtime ||= 'nodejs4.3'
|
86
|
+
timeout ||= 5
|
87
|
+
lambda_client = Aws::Lambda::Client.new(region: @region)
|
66
88
|
begin
|
67
|
-
|
89
|
+
lambda_client.get_alias({function_name: function_name, name: @function_alias})
|
68
90
|
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
69
|
-
|
70
|
-
|
91
|
+
lambda_response = nil
|
92
|
+
zip_file_content = File.read(File.join(@output_path, "#{@function_alias}.zip"))
|
71
93
|
begin
|
72
|
-
|
73
|
-
|
74
|
-
|
94
|
+
lambda_client.get_function({function_name: function_name})
|
95
|
+
lambda_response = lambda_client.update_function_code({function_name: function_name, zip_file: zip_file_content, publish: true})
|
96
|
+
lambda_client.update_function_configuration({function_name: function_name, runtime: runtime, role: lambda_role_arn, handler: handler, description: summary, timeout: timeout})
|
75
97
|
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
76
98
|
puts "Creating new function #{function_name}"
|
77
|
-
|
99
|
+
lambda_response = lambda_client.create_function({function_name: function_name, runtime: runtime, role: lambda_role_arn, handler: handler, code: {zip_file: zip_file_content }, description: summary, publish: true, timeout: timeout})
|
78
100
|
end
|
79
101
|
puts "Creating alias #{@function_alias}"
|
80
|
-
|
81
|
-
|
102
|
+
alias_resp = lambda_client.create_alias({function_name: function_name, name: @function_alias, function_version: lambda_response.version, description: "Deployment of new version on " + Time.now.inspect})
|
103
|
+
lambda_client.add_permission({function_name: alias_resp.alias_arn, statement_id: "API_2_#{function_name}_#{@function_alias}", action: "lambda:*", principal: 'apigateway.amazonaws.com'})
|
82
104
|
end
|
83
105
|
return "arn:aws:apigateway:#{@region}:lambda:path/2015-03-31/functions/arn:aws:lambda:#{@region}:#{@account}:function:#{function_name}:#{@function_alias}/invocations"
|
84
106
|
end
|
85
107
|
|
86
108
|
def get_current_package_alias
|
87
|
-
zipFiles = Dir["#{@
|
109
|
+
zipFiles = Dir["#{@output_path}/*.zip"]
|
88
110
|
if zipFiles.length == 0 then
|
89
111
|
raise 'No package in the output folder. Unable to continue.'
|
90
112
|
elsif zipFiles.length == 0
|
91
113
|
raise 'Multiple package in the output folder. Unable to continue.'
|
92
114
|
end
|
93
|
-
|
115
|
+
File.basename(zipFiles.first, '.zip')
|
94
116
|
end
|
95
117
|
|
96
118
|
def create_api_gateway(swagger)
|
97
119
|
puts "Creating API Gateway"
|
98
|
-
apis = @
|
120
|
+
apis = @api_gateway_client.get_rest_apis(limit: 500).data
|
99
121
|
api = apis.items.select { |a| a.name == swagger['info']['title'] }.first
|
100
122
|
|
101
123
|
if api then
|
102
|
-
resp = @
|
124
|
+
resp = @api_gateway_client.put_rest_api({rest_api_id: api.id, mode: "overwrite", fail_on_warnings: true, body: swagger.to_yaml})
|
103
125
|
else
|
104
|
-
resp = @
|
126
|
+
resp = @api_gateway_client.import_rest_api({fail_on_warnings: true, body: swagger.to_yaml})
|
105
127
|
end
|
106
128
|
|
107
129
|
if resp.warnings then
|
@@ -114,14 +136,16 @@ module Swaggerless
|
|
114
136
|
end
|
115
137
|
|
116
138
|
def create_api_gateway_deployment(lambda_role_arn, swagger)
|
117
|
-
|
118
|
-
|
119
|
-
|
139
|
+
deploy_lambdas_and_update_uris(lambda_role_arn, swagger)
|
140
|
+
deploy_authoirizers_and_update_authorizers_uri(lambda_role_arn, swagger)
|
141
|
+
api_id = self.create_api_gateway(swagger);
|
120
142
|
while true do
|
121
143
|
begin
|
122
144
|
puts "Creating API Gateway Deployment"
|
123
|
-
@
|
124
|
-
|
145
|
+
@api_gateway_client.create_deployment({rest_api_id: api_id, stage_name: @env, description: "Automated deployment of #{@env}", variables: {"env" => @env }});
|
146
|
+
url = "https://#{api_id}.execute-api.#{@region}.amazonaws.com/#{@env}/"
|
147
|
+
puts "API available at #{url}"
|
148
|
+
return url;
|
125
149
|
rescue Aws::APIGateway::Errors::TooManyRequestsException => e
|
126
150
|
STDERR.puts 'WARNING: Got TooManyRequests response from API Gateway. Waiting for a second.'
|
127
151
|
sleep(1)
|
@@ -130,6 +154,55 @@ module Swaggerless
|
|
130
154
|
|
131
155
|
end
|
132
156
|
|
157
|
+
private
|
158
|
+
|
159
|
+
def get_lambda_map(swagger)
|
160
|
+
lambdas_map = Hash.new
|
161
|
+
swagger["paths"].each do |path, path_config|
|
162
|
+
path_config.each do |method, method_config|
|
163
|
+
if lambdas_map[method_config[EXT_LAMBDA_NAME]] then
|
164
|
+
stored_version = lambdas_map[method_config[EXT_LAMBDA_NAME]];
|
165
|
+
encountered_version = build_lambda_config_hash(method_config)
|
166
|
+
unless is_lambda_config_correct(stored_version, encountered_version) then
|
167
|
+
raise "Lambda #{method_config[EXT_LAMBDA_NAME]} mentioned multiple times in configuration with different settings"
|
168
|
+
end
|
169
|
+
lambdas_map[method_config[EXT_LAMBDA_NAME]]['description'] = 'Part of ' + Deployer.get_service_prefix(swagger)
|
170
|
+
else
|
171
|
+
lambdas_map[method_config[EXT_LAMBDA_NAME]] = build_lambda_config_hash(method_config)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
swagger["securityDefinitions"].each do |securityDefinitionName, securityDefinition|
|
177
|
+
if securityDefinition[AMZ_APIGATEWAY_AUTHORIZER] != nil then
|
178
|
+
if lambdas_map[securityDefinition[EXT_LAMBDA_NAME]] then
|
179
|
+
stored_version = lambdas_map[securityDefinition[AMZ_APIGATEWAY_AUTHORIZER][EXT_LAMBDA_NAME]];
|
180
|
+
encountered_version = build_lambda_config_hash(securityDefinition[AMZ_APIGATEWAY_AUTHORIZER])
|
181
|
+
unless is_lambda_config_correct(stored_version, encountered_version)
|
182
|
+
raise "Lambda #{method_config[EXT_LAMBDA_NAME]} mentioned multiple times in configuration with different settings"
|
183
|
+
end
|
184
|
+
lambdas_map[securityDefinition[EXT_LAMBDA_NAME]].description = 'Part of ' + Deployer.get_service_prefix(swagger)
|
185
|
+
else
|
186
|
+
lambdas_map[securityDefinition[EXT_LAMBDA_NAME]] = build_lambda_config_hash(securityDefinition)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
return lambdas_map
|
191
|
+
end
|
192
|
+
|
193
|
+
def is_lambda_config_correct(l1, l2)
|
194
|
+
return (l1['handler'] == l2['handler'] and
|
195
|
+
l1['timeout'] == l2['timeout'] and
|
196
|
+
l1['runtime'] == l2['runtime'])
|
197
|
+
end
|
198
|
+
|
199
|
+
def build_lambda_config_hash(method_config)
|
200
|
+
{ handler: method_config[EXT_LAMBDA_HANDLER],
|
201
|
+
timeout: method_config[EXT_LAMBDA_TIMEOUT],
|
202
|
+
runtime: method_config[EXT_LAMBDA_RUNTIME],
|
203
|
+
description: method_config[SWGR_SUMMARY]}
|
204
|
+
end
|
205
|
+
|
133
206
|
end
|
134
207
|
|
135
208
|
end
|
data/lib/swaggerless/version.rb
CHANGED
data/lib/tasks/swaggerless.rake
CHANGED
@@ -3,50 +3,55 @@ require "json"
|
|
3
3
|
require "swaggerless"
|
4
4
|
require 'fileutils'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
namespace :swaggerless do
|
7
|
+
|
8
|
+
desc 'Deploys to an environment specified as parameter'
|
9
|
+
task :deploy, [ :environment ] => [ :clean, :package ] do |t, args|
|
10
|
+
puts "Deploying API Gateway"
|
11
|
+
if not @swaggerSpecFile then
|
12
|
+
@swaggerSpecFile = 'swagger.yaml'
|
13
|
+
STDERR.puts("Swagger file not configured. Trying default ('#{@swaggerSpecFile}'). Set @swaggerSpecFile to point to swagger yaml file if you use different file name")
|
14
|
+
end
|
15
|
+
|
16
|
+
if not @lambdaRoleArn then
|
17
|
+
raise "Unable to continue. Please configue @lambdaRoleArn in the Rakefile"
|
18
|
+
end
|
19
|
+
|
20
|
+
if not @awsRegion then
|
21
|
+
@awsRegion = ENV['AWS_REGION'] || 'eu-west-1'
|
22
|
+
STDERR.puts("AWS Region is not configured. Trying default ('#{@awsRegion}'). Set @awsRegion to point to swagger yaml file if you use different file name")
|
23
|
+
end
|
24
|
+
|
25
|
+
if not @awsAccount then
|
26
|
+
raise "Unable to continue. Please configue @awsAccount in the Rakefile"
|
27
|
+
end
|
28
|
+
|
29
|
+
swagger_content = File.read(@swaggerSpecFile)
|
30
|
+
swagger = YAML.load(swagger_content)
|
31
|
+
ENV["apiUrl"] = Swaggerless::Deployer.new(@awsAccount, @awsRegion, args[:environment].gsub(/[^a-zA-Z0-9_]/, "_")).create_api_gateway_deployment(@lambdaRoleArn, swagger)
|
32
|
+
puts "Setting $apiUrl environment variable to point to the deployed API"
|
12
33
|
end
|
13
34
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
if not @awsRegion then
|
19
|
-
@awsRegion = ENV['AWS_REGION'] || 'eu-west-1'
|
20
|
-
STDERR.puts("AWS Region is not configured. Trying default ('#{@awsRegion}'). Set @awsRegion to point to swagger yaml file if you use different file name")
|
21
|
-
end
|
35
|
+
desc 'Package the project for AWS Lambda'
|
36
|
+
task :package do
|
37
|
+
puts "Packaging"
|
22
38
|
|
23
|
-
|
24
|
-
raise "Unable to continue. Please configue @awsAccount in the Rakefile"
|
25
|
-
end
|
39
|
+
FileUtils.mkdir_p 'output'
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
41
|
+
if not @packageDir then
|
42
|
+
@packageDir = 'src'
|
43
|
+
STDERR.puts("Package directory not configured. Trying default ('#{@packageDir}'). Set @packageDir to point to the directory that should be packaged for AWS Lambda")
|
44
|
+
end
|
31
45
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
FileUtils.mkdir_p 'output'
|
37
|
-
|
38
|
-
if not @packageDir then
|
39
|
-
@packageDir = 'src'
|
40
|
-
STDERR.puts("Package directory not configured. Trying default ('#{@packageDir}'). Set @packageDir to point to the directory that should be packaged for AWS Lambda")
|
46
|
+
swagger_content = File.read(@swaggerSpecFile)
|
47
|
+
swagger = YAML.load(swagger_content)
|
48
|
+
servicePrefix = Swaggerless::Deployer.get_service_prefix(swagger)
|
49
|
+
Swaggerless::Packager.new(@packageDir, "output/#{servicePrefix}").write
|
41
50
|
end
|
42
51
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
52
|
+
desc 'Clean'
|
53
|
+
task :clean do
|
54
|
+
FileUtils.rm_rf('output')
|
55
|
+
end
|
48
56
|
|
49
|
-
desc 'Clean'
|
50
|
-
task :clean do
|
51
|
-
FileUtils.rm_rf('output')
|
52
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swaggerless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rafal Nowosielski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|