lambda_wrap 0.27.0 → 1.0.0
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/lambda_wrap/api_gateway_manager.rb +123 -173
- data/lib/lambda_wrap/api_manager.rb +270 -0
- data/lib/lambda_wrap/aws_service.rb +40 -0
- data/lib/lambda_wrap/dynamo_db_manager.rb +425 -146
- data/lib/lambda_wrap/environment.rb +53 -0
- data/lib/lambda_wrap/lambda_manager.rb +266 -171
- data/lib/lambda_wrap/version.rb +2 -1
- data/lib/lambda_wrap.rb +12 -2
- metadata +9 -8
- data/lib/lambda_wrap/s3_bucket_manager.rb +0 -32
- data/lib/lambda_wrap/zip_file_generator.rb +0 -67
@@ -0,0 +1,53 @@
|
|
1
|
+
module LambdaWrap
|
2
|
+
# Environment class to pass to the deploy and teardown
|
3
|
+
#
|
4
|
+
# @!attribute [r] name
|
5
|
+
# @return [String] The descriptive name of the environment.
|
6
|
+
#
|
7
|
+
# @!attribute [r] description
|
8
|
+
# @return [String] The description of the environment.
|
9
|
+
#
|
10
|
+
# @!attribute [r] variables
|
11
|
+
# @return [Hash] The Hash of environment variables to deploy with the environment.
|
12
|
+
#
|
13
|
+
# @since 1.0
|
14
|
+
class Environment
|
15
|
+
attr_reader :name
|
16
|
+
attr_reader :description
|
17
|
+
attr_reader :variables
|
18
|
+
|
19
|
+
# Constructor
|
20
|
+
#
|
21
|
+
# @param name [String] Name of the environment. Corresponds to the Lambda Alias and API Gateway Stage.
|
22
|
+
# Must be at least 3 characters, and no more than 20 characters.
|
23
|
+
# @param variables [Hash] Environment variables to pass to the API Gateway stage. Must be a flat hash.
|
24
|
+
# Each key must be Alphanumeric (underscores allowed) and no more than 64 characters. Values can have
|
25
|
+
# most special characters, and no more than 512 characters.
|
26
|
+
# @param description [String] Description of the environment for Stage & Alias descriptions. Must not
|
27
|
+
# exceed 256 characters.
|
28
|
+
def initialize(name, variables = {}, description = 'Managed by LambdaWrap')
|
29
|
+
raise ArgumentError, 'name must be provided (String)!' unless name && name.is_a?(String)
|
30
|
+
# Max Alias Name length is 20 characters.
|
31
|
+
raise ArgumentError, "Invalid name format: #{name}" unless /^[a-zA-Z0-9\-\_]{3,20}$/ =~ name
|
32
|
+
@name = name
|
33
|
+
|
34
|
+
raise ArgumentError, 'Variables must be a Hash!' unless variables.is_a?(Hash)
|
35
|
+
variables.each do |key, value|
|
36
|
+
next if /^[0-9a-zA-Z\_]{1,64}$/ =~ key && /^[A-Za-z0-9\-.\_~:\/?#&=,]{1,512}$/ =~ value && value.is_a?(String)
|
37
|
+
raise ArgumentError, "Invalid Format of variables hash: #{key} => #{value}"
|
38
|
+
end
|
39
|
+
|
40
|
+
variables[:environment] = name unless variables[:environment]
|
41
|
+
@variables = variables
|
42
|
+
|
43
|
+
raise ArgumentError, 'Description must be a String!' unless description.is_a?(String)
|
44
|
+
raise ArgumentError, 'Description too long (Max 256)' unless description.length < 256
|
45
|
+
@description = description
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
return @name if @name && @name.is_a?(String)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,208 +1,303 @@
|
|
1
|
-
require '
|
1
|
+
require 'set'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
module LambdaWrap
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
class
|
9
|
-
|
10
|
-
# The constructor does some basic setup
|
11
|
-
# * Validating basic AWS configuration
|
12
|
-
# * Creating the underlying client to interace with the AWS SDK
|
13
|
-
def initialize
|
14
|
-
# AWS lambda client
|
15
|
-
@client = Aws::Lambda::Client.new
|
16
|
-
end
|
17
|
-
|
18
|
-
##
|
19
|
-
# Packages a set of files and node modules into a deployable package.
|
5
|
+
# Lambda Manager class.
|
6
|
+
# Front loads the configuration to the constructor so that the developer can be more declarative with configuration
|
7
|
+
# and deployments.
|
8
|
+
# @since 1.0
|
9
|
+
class Lambda < AwsService
|
10
|
+
# Initializes a Lambda Manager. Frontloaded configuration.
|
20
11
|
#
|
21
|
-
#
|
22
|
-
# [
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
12
|
+
# @param [Hash] options The Configuration for the Lambda
|
13
|
+
# @option options [String] :lambda_name The name you want to assign to the function you are uploading. The function
|
14
|
+
# names appear in the console and are returned in the ListFunctions API. Function names are used to specify
|
15
|
+
# functions to other AWS Lambda API operations, such as Invoke. Note that the length constraint applies only to
|
16
|
+
# the ARN. If you specify only the function name, it is limited to 64 characters in length.
|
17
|
+
# @option options [String] :handler The function within your code that Lambda calls to begin execution.
|
18
|
+
# @option options [String] :role_arn The Amazon Resource Name (ARN) of the IAM role that Lambda assumes when it
|
19
|
+
# executes your function to access any other Amazon Web Services (AWS) resources.
|
20
|
+
# @option options [String] :path_to_zip_file The absolute path to the Deployment Package zip file
|
21
|
+
# @option options [String] :runtime The runtime environment for the Lambda function you are uploading.
|
22
|
+
# @option options [String] :description ('Deployed with LambdaWrap') A short, user-defined function description.
|
23
|
+
# Lambda does not use this value. Assign a meaningful description as you see fit.
|
24
|
+
# @option options [Integer] :timeout (30) The function execution time at which Lambda should terminate the function.
|
25
|
+
# @option options [Integer] :memory_size (128) The amount of memory, in MB, your Lambda function is given. Lambda
|
26
|
+
# uses this memory size to infer the amount of CPU and memory allocated to your function. The value must be a
|
27
|
+
# multiple of 64MB. Minimum: 128, Maximum: 1536.
|
28
|
+
# @option options [Array<String>] :subnet_ids ([]) If your Lambda function accesses resources in a VPC, you provide
|
29
|
+
# this parameter identifying the list of subnet IDs. These must belong to the same VPC. You must provide at least
|
30
|
+
# one security group and one subnet ID to configure VPC access.
|
31
|
+
# @option options [Array<String>] :security_group_ids ([]) If your Lambda function accesses resources in a VPC, you
|
32
|
+
# provide this parameter identifying the list of security group IDs. These must belong to the same VPC. You must
|
33
|
+
# provide at least one security group and one subnet ID.
|
34
|
+
# @option options [Boolean] :delete_unreferenced_versions (true) Option to delete any Lambda Function Versions upon
|
35
|
+
# deployment that do not have an alias pointing to them.
|
36
|
+
def initialize(options)
|
37
|
+
defaults = {
|
38
|
+
description: 'Deployed with LambdaWrap', subnet_ids: [], security_group_ids: [], timeout: 30, memory_size: 128,
|
39
|
+
delete_unreferenced_versions: true
|
40
|
+
}
|
41
|
+
options_with_defaults = options.reverse_merge(defaults)
|
29
42
|
|
30
|
-
|
31
|
-
|
43
|
+
unless (options_with_defaults[:lambda_name]) && (options_with_defaults[:lambda_name].is_a? String)
|
44
|
+
raise ArgumentError, 'lambda_name must be provided (String)!'
|
32
45
|
end
|
46
|
+
@lambda_name = options_with_defaults[:lambda_name]
|
33
47
|
|
34
|
-
|
35
|
-
|
48
|
+
unless (options_with_defaults[:handler]) && (options_with_defaults[:handler].is_a? String)
|
49
|
+
raise ArgumentError, 'handler must be provided (String)!'
|
36
50
|
end
|
51
|
+
@handler = options_with_defaults[:handler]
|
37
52
|
|
38
|
-
|
53
|
+
unless (options_with_defaults[:role_arn]) && (options_with_defaults[:role_arn].is_a? String)
|
54
|
+
raise ArgumentError, 'role_arn must be provided (String)!'
|
55
|
+
end
|
56
|
+
@role_arn = options_with_defaults[:role_arn]
|
57
|
+
|
58
|
+
unless (options_with_defaults[:path_to_zip_file]) && (options_with_defaults[:path_to_zip_file].is_a? String)
|
59
|
+
raise ArgumentError, 'path_to_zip_file must be provided (String)!'
|
60
|
+
end
|
61
|
+
@path_to_zip_file = options_with_defaults[:path_to_zip_file]
|
62
|
+
|
63
|
+
unless (options_with_defaults[:runtime]) && (options_with_defaults[:runtime].is_a? String)
|
64
|
+
raise ArgumentError, 'runtime must be provided (String)!'
|
65
|
+
end
|
66
|
+
|
67
|
+
case options_with_defaults[:runtime]
|
68
|
+
when 'nodejs' then raise ArgumentError, 'AWS Lambda Runtime NodeJS v0.10.42 is deprecated as of April 2017. \
|
69
|
+
Please see: https://forums.aws.amazon.com/ann.jspa?annID=4142'
|
70
|
+
when 'nodejs4.3', 'nodejs6.10', 'java8', 'python2.7', 'python3.6', 'dotnetcore1.0', 'nodejs4.3-edge'
|
71
|
+
@runtime = options_with_defaults[:runtime]
|
72
|
+
else
|
73
|
+
raise ArgumentError, "Invalid Runtime specified: #{options_with_defaults[:runtime]}. Only accepts: \
|
74
|
+
nodejs4.3, nodejs6.10, java8, python2.7, python3.6, dotnetcore1.0, or nodejs4.3-edge"
|
75
|
+
end
|
76
|
+
|
77
|
+
@description = options_with_defaults[:description]
|
78
|
+
|
79
|
+
@timeout = options_with_defaults[:timeout]
|
80
|
+
|
81
|
+
unless (options_with_defaults[:memory_size] % 64).zero? && (options_with_defaults[:memory_size] >= 128) &&
|
82
|
+
(options_with_defaults[:memory_size] <= 1536)
|
83
|
+
raise ArgumentError, 'Invalid Memory Size.'
|
84
|
+
end
|
85
|
+
@memory_size = options_with_defaults[:memory_size]
|
86
|
+
|
87
|
+
# VPC
|
88
|
+
if options_with_defaults[:subnet_ids].empty? ^ options_with_defaults[:security_group_ids].empty?
|
89
|
+
raise ArgumentError, 'Must supply values for BOTH Subnet Ids and Security Group ID if VPC is desired.'
|
90
|
+
end
|
91
|
+
unless options_with_defaults[:subnet_ids].empty?
|
92
|
+
@vpc_configuration = {
|
93
|
+
subnet_ids: options_with_defaults[:subnet_ids],
|
94
|
+
security_group_ids: options_with_defaults[:security_group_ids]
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
@delete_unreferenced_versions = options_with_defaults[:delete_unreferenced_versions]
|
39
99
|
end
|
40
100
|
|
41
|
-
|
42
|
-
#
|
101
|
+
# Deploys the Lambda to the specified Environment. Creates a Lambda Function if one didn't exist.
|
102
|
+
# Updates the Lambda's configuration, Updates the Lambda's Code, publishes a new version, and creates
|
103
|
+
# an alias that points to the newly published version. If the @delete_unreferenced_versions option
|
104
|
+
# is enabled, all Lambda Function versions that don't have an alias pointing to them will be deleted.
|
43
105
|
#
|
44
|
-
#
|
45
|
-
# [
|
46
|
-
# [
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
obj = s3.bucket(bucket).object(key)
|
106
|
+
# @param environment_options [LambdaWrap::Environment] The target Environment to deploy
|
107
|
+
# @param client [Aws::Lambda::Client] Client to use with SDK. Should be passed in by the API class.
|
108
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
109
|
+
def deploy(environment_options, client, region = 'AWS_REGION')
|
110
|
+
super
|
111
|
+
|
112
|
+
puts "Deploying Lambda: #{@lambda_name} to Environment: #{environment_options.name}"
|
52
113
|
|
53
|
-
|
54
|
-
|
55
|
-
File.open(local_lambda_file, 'rb') do |file|
|
56
|
-
version_id = obj.put(body: file).version_id
|
114
|
+
unless File.exist?(@path_to_zip_file)
|
115
|
+
raise ArgumentError, "Deployment Package Zip File does not exist: #{@path_to_zip_file}!"
|
57
116
|
end
|
58
|
-
raise 'Upload to S3 failed' unless version_id
|
59
117
|
|
60
|
-
|
61
|
-
|
118
|
+
lambda_details = retrieve_lambda_details
|
119
|
+
|
120
|
+
if lambda_details.nil?
|
121
|
+
function_version = create_lambda
|
122
|
+
else
|
123
|
+
update_lambda_config
|
124
|
+
function_version = update_lambda_code
|
125
|
+
end
|
126
|
+
|
127
|
+
create_alias(function_version, environment_options.name, environment_options.description)
|
128
|
+
|
129
|
+
cleanup_unused_versions if @delete_unreferenced_versions
|
130
|
+
|
131
|
+
puts "Lambda: #{@lambda_name} successfully deployed!"
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
# Tearsdown an Environment. Deletes an alias with the same name as the environment. Deletes
|
136
|
+
# Unreferenced Lambda Function Versions if the option was specified.
|
137
|
+
#
|
138
|
+
# @param environment_options [LambdaWrap::Environment] The target Environment to teardown.
|
139
|
+
# @param client [Aws::Lambda::Client] Client to use with SDK. Should be passed in by the API class.
|
140
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
141
|
+
def teardown(environment_options, client, region = 'AWS_REGION')
|
142
|
+
super
|
143
|
+
remove_alias(environment_options.name)
|
144
|
+
cleanup_unused_versions if @delete_unreferenced_versions
|
145
|
+
true
|
62
146
|
end
|
63
147
|
|
64
|
-
|
65
|
-
# Deploys a package that has been uploaded to S3.
|
148
|
+
# Deletes the Lambda Object with associated versions, code, configuration, and aliases.
|
66
149
|
#
|
67
|
-
#
|
68
|
-
# [
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# create or update function
|
150
|
+
# @param client [Aws::Lambda::Client] Client to use with SDK. Should be passed in by the API class.
|
151
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
152
|
+
def delete(client, region = 'AWS_REGION')
|
153
|
+
super
|
154
|
+
puts "Deleting all versions and aliases for Lambda: #{@lambda_name}"
|
155
|
+
lambda_details = retrieve_lambda_details
|
156
|
+
if lambda_details.nil?
|
157
|
+
puts 'No Lambda to delete.'
|
158
|
+
else
|
159
|
+
@client.delete_function(function_name: @lambda_name)
|
160
|
+
puts "Lambda #{@lambda_name} and all Versions & Aliases have been deleted."
|
161
|
+
end
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
165
|
+
def to_s
|
166
|
+
return @lambda_name if @lambda_name && @lambda_name.is_a?(String)
|
167
|
+
super
|
168
|
+
end
|
87
169
|
|
170
|
+
private
|
171
|
+
|
172
|
+
def retrieve_lambda_details
|
173
|
+
lambda_details = nil
|
88
174
|
begin
|
89
|
-
@client.get_function(function_name:
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
description: lambda_description,
|
100
|
-
vpc_config: vpc_configuration
|
101
|
-
).data
|
102
|
-
puts func_config
|
103
|
-
|
104
|
-
func_config = @client.update_function_code(
|
105
|
-
function_name: function_name, s3_bucket: bucket, s3_key: key,
|
106
|
-
s3_object_version: version_id, publish: true
|
107
|
-
).data
|
108
|
-
|
109
|
-
puts func_config
|
110
|
-
func_version = func_config.version
|
111
|
-
raise 'Error while publishing existing lambda function ' + function_name unless func_version
|
112
|
-
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
113
|
-
# check if vpc_subnet_ids and vpc_security_group_ids are empty or not and set the vpc_config accordingly.
|
114
|
-
if vpc_subnet_ids.empty? && vpc_security_group_ids.empty?
|
115
|
-
vpc_configuration = nil
|
116
|
-
else
|
117
|
-
vpc_configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids }
|
118
|
-
end
|
175
|
+
lambda_details = @client.get_function(function_name: @lambda_name).configuration
|
176
|
+
rescue Aws::Lambda::Errors::ResourceNotFoundException, Aws::Lambda::Errors::NotFound
|
177
|
+
puts "Lambda #{@lambda_name} does not exist."
|
178
|
+
end
|
179
|
+
lambda_details
|
180
|
+
end
|
181
|
+
|
182
|
+
def create_lambda
|
183
|
+
puts "Creating New Lambda Function: #{@lambda_name}...."
|
184
|
+
puts "Runtime Engine: #{@runtime}, Timeout: #{@timeout}, Memory Size: #{@memory_size}."
|
119
185
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
186
|
+
lambda_version = @client.create_function(
|
187
|
+
function_name: @lambda_name, runtime: @runtime, role: @role_arn, handler: @handler,
|
188
|
+
code: { zip_file: @path_to_zip_file }, description: @description, timeout: @timeout, memory_size: @memory_size,
|
189
|
+
vpc_config: @vpc_configuration, publish: true
|
190
|
+
).version
|
191
|
+
puts "Successfully created Lambda: #{@lambda_name}!"
|
192
|
+
lambda_version
|
193
|
+
end
|
128
194
|
|
129
|
-
|
130
|
-
|
131
|
-
|
195
|
+
def update_lambda_config
|
196
|
+
puts "Updating Lambda Config for #{@lambda_name}..."
|
197
|
+
puts "Runtime Engine: #{@runtime}, Timeout: #{@timeout}, Memory Size: #{@memory_size}."
|
198
|
+
if @vpc_configuration
|
199
|
+
puts "With VPC Configuration: Subnets: #{@vpc_configuration[:subnet_ids]}, Security Groups: \
|
200
|
+
#{@vpc_configuration[:security_group_ids]}"
|
132
201
|
end
|
133
202
|
|
134
|
-
|
203
|
+
@client.update_function_configuration(
|
204
|
+
function_name: @lambda_name, role: @role_arn, handler: @handler, description: @description, timeout: @timeout,
|
205
|
+
memory_size: @memory_size, vpc_config: @vpc_configuration, runtime: @runtime
|
206
|
+
)
|
135
207
|
|
136
|
-
|
137
|
-
func_version
|
208
|
+
puts "Successfully updated Lambda configuration for #{@lambda_name}"
|
138
209
|
end
|
139
210
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
211
|
+
def update_lambda_code
|
212
|
+
puts "Updating Lambda Code for #{@lambda_name}...."
|
213
|
+
|
214
|
+
response = @client.update_function_code(
|
215
|
+
function_name: @lambda_name,
|
216
|
+
zip_file: File.open(@path_to_zip_file, 'rb').read,
|
217
|
+
publish: true
|
218
|
+
)
|
219
|
+
|
220
|
+
puts "Successully updated Lambda #{@lambda_name} code to version: #{response.version}"
|
221
|
+
response.version
|
222
|
+
end
|
223
|
+
|
224
|
+
def create_alias(func_version, alias_name, alias_description)
|
225
|
+
if alias_exist?(alias_name)
|
226
|
+
@client.update_alias(
|
227
|
+
function_name: @lambda_name, name: alias_name, function_version: func_version,
|
228
|
+
description: alias_description || 'Alias managed by LambdaWrap'
|
229
|
+
)
|
230
|
+
else
|
231
|
+
@client.create_alias(
|
232
|
+
function_name: @lambda_name, name: alias_name, function_version: func_version,
|
233
|
+
description: alias_description || 'Alias managed by LambdaWrap'
|
234
|
+
)
|
235
|
+
end
|
236
|
+
puts "Created Alias: #{alias_name} for Lambda: #{@lambda_name} v#{func_version}."
|
237
|
+
end
|
238
|
+
|
239
|
+
def remove_alias(alias_name)
|
240
|
+
puts "Deleting Alias: #{alias_name} for #{@lambda_name}"
|
241
|
+
@client.delete_alias(function_name: @lambda_name, name: alias_name)
|
242
|
+
end
|
243
|
+
|
244
|
+
def cleanup_unused_versions
|
245
|
+
puts "Cleaning up unused function versions for #{@lambda_name}."
|
246
|
+
function_versions_to_be_deleted = retrieve_all_function_versions -
|
247
|
+
retrieve_function_versions_used_in_aliases
|
248
|
+
|
249
|
+
return if function_versions_to_be_deleted.empty?
|
250
|
+
|
251
|
+
function_versions_to_be_deleted.each do |version|
|
252
|
+
puts "Deleting function version: #{version}."
|
253
|
+
@client.delete_function(function_name: @lambda_name, qualifier: version)
|
254
|
+
end
|
255
|
+
|
256
|
+
puts "Cleaned up #{function_versions_to_be_deleted.length} unused versions."
|
257
|
+
end
|
258
|
+
|
259
|
+
def retrieve_all_function_versions
|
260
|
+
function_versions = []
|
261
|
+
response = nil
|
262
|
+
loop do
|
263
|
+
response =
|
264
|
+
if !response || response.next_marker.nil? || response.next_marker.empty?
|
265
|
+
@client.list_versions_by_function(function_name: @lambda_name)
|
155
266
|
else
|
156
|
-
@client.
|
157
|
-
function_name: function_name, name: alias_name, function_version: func_version,
|
158
|
-
description: 'updated by an automated script'
|
159
|
-
).data
|
267
|
+
@client.list_versions_by_function(function_name: @lambda_name, marker: response.next_marker)
|
160
268
|
end
|
161
|
-
|
269
|
+
function_versions.concat(response.versions.map(&:version))
|
270
|
+
if response.next_marker.nil? || response.next_marker.empty?
|
271
|
+
return function_versions.reject { |v| v == '$LATEST' }
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
162
275
|
|
163
|
-
|
276
|
+
def retrieve_all_aliases
|
277
|
+
aliases = []
|
278
|
+
response = nil
|
279
|
+
loop do
|
280
|
+
response = invoke_client_method_with_optional_marker(response, :list_aliases)
|
281
|
+
aliases.concat(response.aliases)
|
282
|
+
return aliases if response.aliases.empty? || response.next_marker.nil? || response.next_marker.empty?
|
283
|
+
end
|
164
284
|
end
|
165
285
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# *Arguments*
|
170
|
-
# [function_name] The lambda function name for which the alias should be removed.
|
171
|
-
# [alias_name] The alias to remove.
|
172
|
-
def remove_alias(function_name, alias_name)
|
173
|
-
@client.delete_alias(function_name: function_name, name: alias_name)
|
286
|
+
def retrieve_function_versions_used_in_aliases
|
287
|
+
function_versions_with_aliases = Set.new []
|
288
|
+
function_versions_with_aliases.merge(retrieve_all_aliases.map(&:function_version)).to_a
|
174
289
|
end
|
175
290
|
|
176
|
-
|
177
|
-
|
178
|
-
#
|
179
|
-
# *Arguments*
|
180
|
-
# [function_name] The function name which needs to be executed from API Gateway.
|
181
|
-
# [env] The environment (matching the function's alias) which needs to be executed from API Gateway.
|
182
|
-
# => If nil, the permissions are set of the $LATEST version.
|
183
|
-
def add_api_gateway_permissions(function_name, env)
|
184
|
-
# permissions to execute lambda
|
185
|
-
suffix = (':' + env if env) || ''
|
186
|
-
func = @client.get_function(function_name: function_name + suffix).data.configuration
|
187
|
-
statement_id = func.function_name + (('-' + env if env) || '')
|
188
|
-
begin
|
189
|
-
existing_policies = @client.get_policy(function_name: func.function_arn).data
|
190
|
-
existing_policy = JSON.parse(existing_policies.policy)
|
191
|
-
policy_exists = existing_policy['Statement'].select { |s| s['Sid'] == statement_id }.any?
|
192
|
-
rescue Aws::Lambda::Errors::ResourceNotFoundException
|
193
|
-
# policy does not exist, and that is ok
|
194
|
-
policy_exists = false
|
195
|
-
end
|
196
|
-
|
197
|
-
unless policy_exists
|
198
|
-
perm_add = @client.add_permission(
|
199
|
-
function_name: func.function_arn, statement_id: statement_id,
|
200
|
-
action: 'lambda:*', principal: 'apigateway.amazonaws.com'
|
201
|
-
)
|
202
|
-
puts perm_add.data
|
203
|
-
end
|
291
|
+
def alias_exist?(alias_name)
|
292
|
+
retrieve_all_aliases.detect { |a| a.name == alias_name }
|
204
293
|
end
|
205
294
|
|
206
|
-
|
295
|
+
def invoke_client_method_with_optional_marker(response, method_symbol)
|
296
|
+
if !response || response.next_marker.nil? || response.next_marker.empty?
|
297
|
+
@client.send(method_symbol, function_name: @lambda_name)
|
298
|
+
else
|
299
|
+
@client.send(method_symbol, function_name: @lambda_name, marker: response.next_marker)
|
300
|
+
end
|
301
|
+
end
|
207
302
|
end
|
208
303
|
end
|
data/lib/lambda_wrap/version.rb
CHANGED
data/lib/lambda_wrap.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'lambda_wrap/version'
|
2
|
+
|
3
|
+
require 'aws-sdk'
|
4
|
+
require 'yaml'
|
5
|
+
require 'active_support/core_ext/hash'
|
6
|
+
|
7
|
+
require 'lambda_wrap/aws_service'
|
8
|
+
require 'lambda_wrap/lambda_manager'
|
9
|
+
require 'lambda_wrap/dynamo_db_manager'
|
10
|
+
require 'lambda_wrap/api_gateway_manager'
|
11
|
+
require 'lambda_wrap/environment'
|
12
|
+
require 'lambda_wrap/api_manager'
|
3
13
|
|
4
14
|
STDOUT.sync = true
|
5
15
|
STDERR.sync = true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lambda_wrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Thurner
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-
|
13
|
+
date: 2017-05-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk
|
@@ -27,19 +27,19 @@ dependencies:
|
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '2'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
30
|
+
name: activesupport
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: '
|
35
|
+
version: '4'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '4'
|
43
43
|
description: |-
|
44
44
|
This gem wraps the AWS SDK to simplify deployment of AWS \
|
45
45
|
Lambda functions backed by API Gateway and DynamoDB.
|
@@ -51,11 +51,12 @@ extra_rdoc_files: []
|
|
51
51
|
files:
|
52
52
|
- lib/lambda_wrap.rb
|
53
53
|
- lib/lambda_wrap/api_gateway_manager.rb
|
54
|
+
- lib/lambda_wrap/api_manager.rb
|
55
|
+
- lib/lambda_wrap/aws_service.rb
|
54
56
|
- lib/lambda_wrap/dynamo_db_manager.rb
|
57
|
+
- lib/lambda_wrap/environment.rb
|
55
58
|
- lib/lambda_wrap/lambda_manager.rb
|
56
|
-
- lib/lambda_wrap/s3_bucket_manager.rb
|
57
59
|
- lib/lambda_wrap/version.rb
|
58
|
-
- lib/lambda_wrap/zip_file_generator.rb
|
59
60
|
homepage: https://github.com/Cimpress-MCP/LambdaWrap
|
60
61
|
licenses:
|
61
62
|
- Apache-2.0
|
@@ -68,7 +69,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
69
|
requirements:
|
69
70
|
- - ">="
|
70
71
|
- !ruby/object:Gem::Version
|
71
|
-
version:
|
72
|
+
version: 1.9.3
|
72
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
74
|
requirements:
|
74
75
|
- - ">="
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'aws-sdk'
|
2
|
-
|
3
|
-
module LambdaWrap
|
4
|
-
##
|
5
|
-
# The S3BucketManager would have functions to help add policies, CORS etc to S3 bucket.
|
6
|
-
class S3BucketManager
|
7
|
-
#
|
8
|
-
# The constructor creates an instance of s3 bucket
|
9
|
-
# * Validating basic AWS configuration
|
10
|
-
# * Creating the underlying client to interact with the AWS SDK.
|
11
|
-
# * Defining the temporary path of the api-gateway-importer jar file
|
12
|
-
def initialize
|
13
|
-
@s3bucket = Aws::S3::Client.new
|
14
|
-
end
|
15
|
-
|
16
|
-
##
|
17
|
-
# Adds policy to the bucket
|
18
|
-
#
|
19
|
-
# *Arguments*
|
20
|
-
# [s3_bucket_name] S3 bucket name.
|
21
|
-
# [policy] Policy to be added to the bucket
|
22
|
-
def setup_policy(s3_bucket_name, policy)
|
23
|
-
# Validate the parameters
|
24
|
-
raise 'S3 bucket is not provided' unless s3_bucket_name
|
25
|
-
raise 'Policy json is not provided' unless policy
|
26
|
-
|
27
|
-
@s3bucket.put_bucket_policy(bucket: s3_bucket_name,
|
28
|
-
policy: policy.to_json)
|
29
|
-
puts "Created/Updated policy: #{policy} in S3 bucket #{s3_bucket_name}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|