lambda_wrap 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 967cbf57b49c5c9089d2b7fb499e918e06b0c2cd
4
- data.tar.gz: e04be077d970608457c40613e8c42cb41364822f
3
+ metadata.gz: 538942578f2271e578436d168e5cbc84e7691bb0
4
+ data.tar.gz: 6f25cf394a08908a0bbb39bf924a75c9dc36d216
5
5
  SHA512:
6
- metadata.gz: ce0921cb5e342d7b6dee2caec10bc1c0f7ac73f240f3fd3a8afd0dff72cf7137bdd1b0203871713eac296384352a095c59fdd4a2857cd751d466dbb5f293bfe7
7
- data.tar.gz: 722c438455fc50aabdb5528ee568679f6920aef78291591ae9b249c785f1ff09dd2989e754b5ca684443fb0f5cb2141704236e6faadca3887570edbe231f58ec
6
+ metadata.gz: 06931dad00016c68f3b5064b6a368f9833dd4f818e5e3a09eb2f5467353773c6f37cd2194ab00e76647bfc7ec3d20c361801bd1962eac4da7cb7ef31b0203d88
7
+ data.tar.gz: 6128b14ac5a3cc406b0e604b9a509f00bc7b536c3a350f829e7f7fb85ca3d4c7384bbc4758ddaeaf49265d8ad001210c275d363f76114dc19e297a506993fca2
@@ -1,121 +1,121 @@
1
- require 'aws-sdk'
2
-
3
- module LambdaWrap
4
- # The DynamoDBManager simplifies setting up and destroying a DynamoDB database.
5
- #
6
- # Note: In case an environment specific DynamoDB tablename such as +<baseTableName>-production+ should be used, then
7
- # it has to be injected directly to the methods since not all environments necessarily need separated databases.
8
- class DynamoDbManager
9
- ##
10
- # The constructor does some basic setup
11
- # * Validating basic AWS configuration
12
- # * Creating the underlying client to interact with the AWS SDK.
13
- def initialize
14
- # AWS dynamodb client
15
- @client = Aws::DynamoDB::Client.new
16
- end
17
-
18
- def set_table_capacity(table_name, read_capacity, write_capacity)
19
- puts "Updating new read/write capacity for table #{table_name}.
20
- Read #{table_details.provisioned_throughput.read_capacity_units} ==> #{read_capacity}.
21
- Write #{table_details.provisioned_throughput.write_capacity_units} ==> #{write_capacity}."
22
- @client.update_table(
23
- table_name: table_name,
24
- provisioned_throughput: { read_capacity_units: read_capacity, write_capacity_units: write_capacity }
25
- )
26
- end
27
-
28
- ##
29
- # Publishes the database and awaits until it is fully available. If the table already exists,
30
- # it only adjusts the read and write
31
- # capacities upwards (it doesn't downgrade them to avoid a production environment being impacted with
32
- # a default setting of an automated script).
33
- #
34
- # *Arguments*
35
- # [table_name] The table name of the dynamoDB to be created.
36
- # [attribute_definitions] The dynamoDB attribute definitions to be used when the table is created.
37
- # [key_schema] The dynamoDB key definitions to be used when the table is created.
38
- # [read_capacity] The read capacity to configure for the dynamoDB table.
39
- # [write_capacity] The write capacity to configure for the dynamoDB table.
40
- def publish_database(table_name, attribute_definitions, key_schema, read_capacity, write_capacity)
41
- has_updates = false
42
-
43
- # figure out whether the table exists
44
- begin
45
- table_details = @client.describe_table(table_name: table_name).table
46
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
47
- # skip this exception because we are using it for control flow.
48
- table_details = nil
49
- end
50
-
51
- if table_details
52
- wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
53
-
54
- if read_capacity > table_details.provisioned_throughput.read_capacity_units ||
55
- write_capacity > table_details.provisioned_throughput.write_capacity_units
56
-
57
- set_table_capacity read_capacity, write_capacity
58
- has_updates = true
59
- else
60
- puts "Table #{table_name} already exists and the desired read capacity of #{read_capacity} and " \
61
- "write capacity of #{write_capacity} has at least been configured. Downgrading capacity units is not " \
62
- 'supported. No changes were applied.'
63
- end
64
- else
65
- puts "Creating table #{table_name}."
66
- ad = attribute_definitions || [{ attribute_name: 'Id', attribute_type: 'S' }]
67
- ks = key_schema || [{ attribute_name: 'Id', key_type: 'HASH' }]
68
- @client.create_table(table_name: table_name, key_schema: ks, attribute_definitions: ad,
69
- provisioned_throughput:
70
- { read_capacity_units: read_capacity, write_capacity_units: write_capacity })
71
- has_updates = true
72
- end
73
-
74
- if has_updates
75
- wait_until_table_available(table_name)
76
- puts "DynamoDB table #{table_name} is now fully available."
77
- end
78
- end
79
-
80
- ##
81
- # Deletes a DynamoDB table. It does not wait until the table has been deleted.
82
- #
83
- # *Arguments*
84
- # [table_name] The dynamoDB table name to delete.
85
- def delete_database(table_name)
86
- table_details = @client.describe_table(table_name: table_name).table
87
- wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
88
- @client.delete_table(table_name: table_name)
89
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
90
- puts 'Table did not exist. Nothing to delete.'
91
- end
92
-
93
- ##
94
- # Awaits a given status of a table.
95
- #
96
- # *Arguments*
97
- # [table_name] The dynamoDB table name to watch until it reaches an active status.
98
- def wait_until_table_available(table_name)
99
- max_attempts = 24
100
- delay_between_attempts = 5
101
-
102
- # wait until the table has updated to being fully available
103
- # waiting for ~2min at most; an error will be thrown afterwards
104
- begin
105
- @client.wait_until(:table_exists, table_name: table_name) do |w|
106
- w.max_attempts = max_attempts
107
- w.delay = delay_between_attempts
108
- w.before_wait do |attempts, _|
109
- puts "Waiting until table becomes available. Attempt #{attempts}/#{max_attempts} " \
110
- "with polling interval #{delay_between_attempts}."
111
- end
112
- end
113
- rescue Aws::Waiters::Errors::TooManyAttemptsError => e
114
- puts "Table #{table_name} did not become available after #{e.attempts} attempts. " \
115
- 'Try again later or inspect the AWS console.'
116
- end
117
- end
118
-
119
- private :wait_until_table_available
120
- end
121
- end
1
+ require 'aws-sdk'
2
+
3
+ module LambdaWrap
4
+ # The DynamoDBManager simplifies setting up and destroying a DynamoDB database.
5
+ #
6
+ # Note: In case an environment specific DynamoDB tablename such as +<baseTableName>-production+ should be used, then
7
+ # it has to be injected directly to the methods since not all environments necessarily need separated databases.
8
+ class DynamoDbManager
9
+ ##
10
+ # The constructor does some basic setup
11
+ # * Validating basic AWS configuration
12
+ # * Creating the underlying client to interact with the AWS SDK.
13
+ def initialize
14
+ # AWS dynamodb client
15
+ @client = Aws::DynamoDB::Client.new
16
+ end
17
+
18
+ def set_table_capacity(table_name, read_capacity, write_capacity)
19
+ puts "Updating new read/write capacity for table #{table_name}.
20
+ Read #{table_details.provisioned_throughput.read_capacity_units} ==> #{read_capacity}.
21
+ Write #{table_details.provisioned_throughput.write_capacity_units} ==> #{write_capacity}."
22
+ @client.update_table(
23
+ table_name: table_name,
24
+ provisioned_throughput: { read_capacity_units: read_capacity, write_capacity_units: write_capacity }
25
+ )
26
+ end
27
+
28
+ ##
29
+ # Publishes the database and awaits until it is fully available. If the table already exists,
30
+ # it only adjusts the read and write
31
+ # capacities upwards (it doesn't downgrade them to avoid a production environment being impacted with
32
+ # a default setting of an automated script).
33
+ #
34
+ # *Arguments*
35
+ # [table_name] The table name of the dynamoDB to be created.
36
+ # [attribute_definitions] The dynamoDB attribute definitions to be used when the table is created.
37
+ # [key_schema] The dynamoDB key definitions to be used when the table is created.
38
+ # [read_capacity] The read capacity to configure for the dynamoDB table.
39
+ # [write_capacity] The write capacity to configure for the dynamoDB table.
40
+ def publish_database(table_name, attribute_definitions, key_schema, read_capacity, write_capacity)
41
+ has_updates = false
42
+
43
+ # figure out whether the table exists
44
+ begin
45
+ table_details = @client.describe_table(table_name: table_name).table
46
+ rescue Aws::DynamoDB::Errors::ResourceNotFoundException
47
+ # skip this exception because we are using it for control flow.
48
+ table_details = nil
49
+ end
50
+
51
+ if table_details
52
+ wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
53
+
54
+ if read_capacity > table_details.provisioned_throughput.read_capacity_units ||
55
+ write_capacity > table_details.provisioned_throughput.write_capacity_units
56
+
57
+ set_table_capacity read_capacity, write_capacity
58
+ has_updates = true
59
+ else
60
+ puts "Table #{table_name} already exists and the desired read capacity of #{read_capacity} and " \
61
+ "write capacity of #{write_capacity} has at least been configured. Downgrading capacity units is not " \
62
+ 'supported. No changes were applied.'
63
+ end
64
+ else
65
+ puts "Creating table #{table_name}."
66
+ ad = attribute_definitions || [{ attribute_name: 'Id', attribute_type: 'S' }]
67
+ ks = key_schema || [{ attribute_name: 'Id', key_type: 'HASH' }]
68
+ @client.create_table(table_name: table_name, key_schema: ks, attribute_definitions: ad,
69
+ provisioned_throughput:
70
+ { read_capacity_units: read_capacity, write_capacity_units: write_capacity })
71
+ has_updates = true
72
+ end
73
+
74
+ if has_updates
75
+ wait_until_table_available(table_name)
76
+ puts "DynamoDB table #{table_name} is now fully available."
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Deletes a DynamoDB table. It does not wait until the table has been deleted.
82
+ #
83
+ # *Arguments*
84
+ # [table_name] The dynamoDB table name to delete.
85
+ def delete_database(table_name)
86
+ table_details = @client.describe_table(table_name: table_name).table
87
+ wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
88
+ @client.delete_table(table_name: table_name)
89
+ rescue Aws::DynamoDB::Errors::ResourceNotFoundException
90
+ puts 'Table did not exist. Nothing to delete.'
91
+ end
92
+
93
+ ##
94
+ # Awaits a given status of a table.
95
+ #
96
+ # *Arguments*
97
+ # [table_name] The dynamoDB table name to watch until it reaches an active status.
98
+ def wait_until_table_available(table_name)
99
+ max_attempts = 24
100
+ delay_between_attempts = 5
101
+
102
+ # wait until the table has updated to being fully available
103
+ # waiting for ~2min at most; an error will be thrown afterwards
104
+ begin
105
+ @client.wait_until(:table_exists, table_name: table_name) do |w|
106
+ w.max_attempts = max_attempts
107
+ w.delay = delay_between_attempts
108
+ w.before_wait do |attempts, _|
109
+ puts "Waiting until table becomes available. Attempt #{attempts}/#{max_attempts} " \
110
+ "with polling interval #{delay_between_attempts}."
111
+ end
112
+ end
113
+ rescue Aws::Waiters::Errors::TooManyAttemptsError => e
114
+ puts "Table #{table_name} did not become available after #{e.attempts} attempts. " \
115
+ 'Try again later or inspect the AWS console.'
116
+ end
117
+ end
118
+
119
+ private :wait_until_table_available
120
+ end
121
+ end
@@ -1,188 +1,194 @@
1
- require 'aws-sdk'
2
-
3
- module LambdaWrap
4
- ##
5
- # The LambdaManager simplifies creating a package, publishing to S3, deploying a new version, & setting permissions.
6
- #
7
- # Note: The concept of an environment of the LambdaWrap gem matches an alias of AWS Lambda.
8
- class LambdaManager
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.
20
- #
21
- # *Arguments*
22
- # [directory] A temporary directory to copy all related files before they are packages into a single zip file.
23
- # [zipfile] A path where the deployable package, a zip file, should be stored.
24
- # [input_filenames] A list of file names that contain the source code.
25
- # [node_modules] A list of node modules that need to be included in the package.
26
- def package(directory, zipfile, input_filenames, node_modules)
27
- FileUtils.mkdir_p directory
28
- FileUtils.mkdir_p File.join(directory, 'node_modules')
29
-
30
- input_filenames.each do |filename|
31
- FileUtils.copy_file(File.join(filename), File.join(directory, File.basename(filename)))
32
- end
33
-
34
- node_modules.each do |dir|
35
- FileUtils.cp_r(File.join('node_modules', dir), File.join(directory, 'node_modules'))
36
- end
37
-
38
- ZipFileGenerator.new(directory, zipfile).write
39
- end
40
-
41
- ##
42
- # Publishes a package to S3 so it can be deployed as a lambda function.
43
- #
44
- # *Arguments*
45
- # [local_lambda_file] The location of the package that needs to be deployed.
46
- # [bucket] The s3 bucket where the file needs to be uploaded to.
47
- # [key] The S3 path (key) where the package should be stored.
48
- def publish_lambda_to_s3(local_lambda_file, bucket, key)
49
- # get s3 object
50
- s3 = Aws::S3::Resource.new
51
- obj = s3.bucket(bucket).object(key)
52
-
53
- # upload
54
- version_id = nil
55
- File.open(local_lambda_file, 'rb') do |file|
56
- version_id = obj.put(body: file).version_id
57
- end
58
- raise 'Upload to S3 failed' unless version_id
59
-
60
- puts 'Uploaded object to S3 with version ' + version_id
61
- version_id
62
- end
63
-
64
- ##
65
- # Deploys a package that has been uploaded to S3.
66
- #
67
- # *Arguments*
68
- # [bucket] The S3 bucket where the package can be retrieved from.
69
- # [key] The S3 path (key) where the package can be retrieved from.
70
- # [version_id] The version of the file on S3 to retrieve.
71
- # [function_name] The name of the lambda function.
72
- # [handler] The handler that should be executed for this lambda function.
73
- # [lambda_role] The arn of the IAM role that should be used when executing the lambda function.
74
- # [lambda_description] The description of the lambda function.
75
- # [vpc_subnet_ids] A list of subnet ids for the lambda's VPC configuration. All subnets must be on the same VPC.
76
- # [vpc_security_group_ids] A list of security group ids for the lambda's VPC configuration. All of the
77
- # security_group_ids must be on the same VPC.
78
- # [runtime] The runtime the code is written for.
79
- def deploy_lambda(
80
- bucket, key, version_id, function_name, handler, lambda_role, lambda_description = 'Deployed with LambdaWrap',
81
- vpc_subnet_ids = [], vpc_security_group_ids = [], runtime = 'nodejs4.3'
82
- )
83
- # create or update function
84
-
85
- begin
86
- @client.get_function(function_name: function_name)
87
- func_config = @client.update_function_code(function_name: function_name, s3_bucket: bucket, s3_key: key,
88
- s3_object_version: version_id, publish: true).data
89
- puts func_config
90
- vpc_configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids } unless (vpc_subnet_ids.empty? && vpc_security_group_ids.empty?)
91
- func_config = @client.update_function_configuration(function_name: function_name, role: lambda_role, runtime: runtime,
92
- handler: handler, timeout: 5, memory_size: 128,
93
- description: lambda_description,
94
- vpc_config: vpc_configuration).data
95
- puts func_config
96
- func_version = func_config.version
97
- raise 'Error while publishing existing lambda function ' + function_name unless func_version
98
- rescue Aws::Lambda::Errors::ResourceNotFoundException
99
- # check if vpc_subnet_ids and vpc_security_group_ids are empty or not and set the vpc_config accordingly.
100
- vpc_Configuration = nil
101
- vpc_Configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids } unless (vpc_subnet_ids.empty? && vpc_security_group_ids.empty?)
102
-
103
- # if we cannot find it, we have to create it instead of updating it
104
- func_config = @client.create_function(
105
- function_name: function_name, runtime: runtime, role: lambda_role,
106
- handler: handler, code: { s3_bucket: bucket, s3_key: key }, timeout: 5, memory_size: 128, publish: true,
107
- description: lambda_description,
108
- vpc_config: vpc_Configuration
109
- ).data
110
- puts func_config
111
- func_version = func_config.version
112
- raise "Error while publishing new lambda function #{function_name}" unless func_version
113
- end
114
-
115
- add_api_gateway_permissions(function_name, nil)
116
-
117
- func_version
118
- end
119
-
120
- ##
121
- # Creates an alias for a given lambda function version.
122
- #
123
- # *Arguments*
124
- # [function_name] The lambda function name for which the alias should be created.
125
- # [func_version] The lambda function versino to which the alias should point.
126
- # [alias_name] The name of the alias, matching the LambdaWrap environment concept.
127
- def create_alias(function_name, func_version, alias_name)
128
- # create or update alias
129
- func_alias = @client.list_aliases(function_name: function_name).aliases.select { |a| a.name == alias_name }.first
130
- if !func_alias
131
- a = @client.create_alias(
132
- function_name: function_name, name: alias_name, function_version: func_version,
133
- description: 'created by an automated script'
134
- ).data
135
- else
136
- a = @client.update_alias(
137
- function_name: function_name, name: alias_name, function_version: func_version,
138
- description: 'updated by an automated script'
139
- ).data
140
- end
141
- puts a
142
-
143
- add_api_gateway_permissions(function_name, alias_name)
144
- end
145
-
146
- ##
147
- # Removes an alias for a function.
148
- #
149
- # *Arguments*
150
- # [function_name] The lambda function name for which the alias should be removed.
151
- # [alias_name] The alias to remove.
152
- def remove_alias(function_name, alias_name)
153
- @client.delete_alias(function_name: function_name, name: alias_name)
154
- end
155
-
156
- ##
157
- # Adds permissions for API gateway to execute this function.
158
- #
159
- # *Arguments*
160
- # [function_name] The function name which needs to be executed from API Gateway.
161
- # [env] The environment (matching the function's alias) which needs to be executed from API Gateway.
162
- # => If nil, the permissions are set of the $LATEST version.
163
- def add_api_gateway_permissions(function_name, env)
164
- # permissions to execute lambda
165
- suffix = (':' + env if env) || ''
166
- func = @client.get_function(function_name: function_name + suffix).data.configuration
167
- statement_id = func.function_name + (('-' + env if env) || '')
168
- begin
169
- existing_policies = @client.get_policy(function_name: func.function_arn).data
170
- existing_policy = JSON.parse(existing_policies.policy)
171
- policy_exists = existing_policy['Statement'].select { |s| s['Sid'] == statement_id }.any?
172
- rescue Aws::Lambda::Errors::ResourceNotFoundException
173
- # policy does not exist, and that is ok
174
- policy_exists = false
175
- end
176
-
177
- unless policy_exists
178
- perm_add = @client.add_permission(
179
- function_name: func.function_arn, statement_id: statement_id,
180
- action: 'lambda:*', principal: 'apigateway.amazonaws.com'
181
- )
182
- puts perm_add.data
183
- end
184
- end
185
-
186
- private :add_api_gateway_permissions
187
- end
188
- end
1
+ require 'aws-sdk'
2
+
3
+ module LambdaWrap
4
+ ##
5
+ # The LambdaManager simplifies creating a package, publishing to S3, deploying a new version, & setting permissions.
6
+ #
7
+ # Note: The concept of an environment of the LambdaWrap gem matches an alias of AWS Lambda.
8
+ class LambdaManager
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.
20
+ #
21
+ # *Arguments*
22
+ # [directory] A temporary directory to copy all related files before they are packages into a single zip file.
23
+ # [zipfile] A path where the deployable package, a zip file, should be stored.
24
+ # [input_filenames] A list of file names that contain the source code.
25
+ # [node_modules] A list of node modules that need to be included in the package.
26
+ def package(directory, zipfile, input_filenames, node_modules)
27
+ FileUtils.mkdir_p directory
28
+ FileUtils.mkdir_p File.join(directory, 'node_modules')
29
+
30
+ input_filenames.each do |filename|
31
+ FileUtils.copy_file(File.join(filename), File.join(directory, File.basename(filename)))
32
+ end
33
+
34
+ node_modules.each do |dir|
35
+ FileUtils.cp_r(File.join('node_modules', dir), File.join(directory, 'node_modules'))
36
+ end
37
+
38
+ ZipFileGenerator.new(directory, zipfile).write
39
+ end
40
+
41
+ ##
42
+ # Publishes a package to S3 so it can be deployed as a lambda function.
43
+ #
44
+ # *Arguments*
45
+ # [local_lambda_file] The location of the package that needs to be deployed.
46
+ # [bucket] The s3 bucket where the file needs to be uploaded to.
47
+ # [key] The S3 path (key) where the package should be stored.
48
+ def publish_lambda_to_s3(local_lambda_file, bucket, key)
49
+ # get s3 object
50
+ s3 = Aws::S3::Resource.new
51
+ obj = s3.bucket(bucket).object(key)
52
+
53
+ # upload
54
+ version_id = nil
55
+ File.open(local_lambda_file, 'rb') do |file|
56
+ version_id = obj.put(body: file).version_id
57
+ end
58
+ raise 'Upload to S3 failed' unless version_id
59
+
60
+ puts 'Uploaded object to S3 with version ' + version_id
61
+ version_id
62
+ end
63
+
64
+ ##
65
+ # Deploys a package that has been uploaded to S3.
66
+ #
67
+ # *Arguments*
68
+ # [bucket] The S3 bucket where the package can be retrieved from.
69
+ # [key] The S3 path (key) where the package can be retrieved from.
70
+ # [version_id] The version of the file on S3 to retrieve.
71
+ # [function_name] The name of the lambda function.
72
+ # [handler] The handler that should be executed for this lambda function.
73
+ # [lambda_role] The arn of the IAM role that should be used when executing the lambda function.
74
+ # [lambda_description] The description of the lambda function.
75
+ # [vpc_subnet_ids] A list of subnet ids for the lambda's VPC configuration. All subnets must be on the same VPC.
76
+ # [vpc_security_group_ids] A list of security group ids for the lambda's VPC configuration. All of the
77
+ # security_group_ids must be on the same VPC.
78
+ # [runtime] The runtime the code is written for.
79
+ # [timeout] The integer value of seconds until the lambda timesout. Minimum 1, Maximum 300
80
+ # [memory_size] The Memory/ProcessingPower allocated for the Lambda. Minimum 128. Maximum 1536. Only accepts
81
+ # integers in multiples of 64.
82
+ def deploy_lambda(
83
+ bucket, key, version_id, function_name, handler, lambda_role, lambda_description = 'Deployed with LambdaWrap',
84
+ vpc_subnet_ids = [], vpc_security_group_ids = [], runtime = 'nodejs4.3', timeout = 5, memory_size = 128
85
+ )
86
+ # create or update function
87
+
88
+ begin
89
+ @client.get_function(function_name: function_name)
90
+ vpc_configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids } unless (vpc_subnet_ids.empty? && vpc_security_group_ids.empty?)
91
+ func_config = @client.update_function_configuration(function_name: function_name, role: lambda_role, runtime: runtime,
92
+ handler: handler, timeout: timeout, memory_size: memory_size,
93
+ description: lambda_description,
94
+ vpc_config: vpc_configuration).data
95
+ puts func_config
96
+
97
+ func_config = @client.update_function_code(function_name: function_name, s3_bucket: bucket, s3_key: key,
98
+ s3_object_version: version_id, publish: true).data
99
+
100
+ puts func_config
101
+ func_version = func_config.version
102
+ raise 'Error while publishing existing lambda function ' + function_name unless func_version
103
+ rescue Aws::Lambda::Errors::ResourceNotFoundException
104
+ # check if vpc_subnet_ids and vpc_security_group_ids are empty or not and set the vpc_config accordingly.
105
+ vpc_Configuration = nil
106
+ vpc_Configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids } unless (vpc_subnet_ids.empty? && vpc_security_group_ids.empty?)
107
+
108
+ # if we cannot find it, we have to create it instead of updating it
109
+ func_config = @client.create_function(
110
+ function_name: function_name, runtime: runtime, role: lambda_role,
111
+ handler: handler, code: { s3_bucket: bucket, s3_key: key }, timeout: timeout, memory_size: memory_size, publish: true,
112
+ description: lambda_description,
113
+ vpc_config: vpc_Configuration
114
+ ).data
115
+ puts func_config
116
+ func_version = func_config.version
117
+ raise "Error while publishing new lambda function #{function_name}" unless func_version
118
+ end
119
+
120
+ add_api_gateway_permissions(function_name, nil)
121
+
122
+ # return the version of the new code, not the config.
123
+ func_version
124
+ end
125
+
126
+ ##
127
+ # Creates an alias for a given lambda function version.
128
+ #
129
+ # *Arguments*
130
+ # [function_name] The lambda function name for which the alias should be created.
131
+ # [func_version] The lambda function versino to which the alias should point.
132
+ # [alias_name] The name of the alias, matching the LambdaWrap environment concept.
133
+ def create_alias(function_name, func_version, alias_name)
134
+ # create or update alias
135
+ func_alias = @client.list_aliases(function_name: function_name).aliases.select { |a| a.name == alias_name }.first
136
+ if !func_alias
137
+ a = @client.create_alias(
138
+ function_name: function_name, name: alias_name, function_version: func_version,
139
+ description: 'created by an automated script'
140
+ ).data
141
+ else
142
+ a = @client.update_alias(
143
+ function_name: function_name, name: alias_name, function_version: func_version,
144
+ description: 'updated by an automated script'
145
+ ).data
146
+ end
147
+ puts a
148
+
149
+ add_api_gateway_permissions(function_name, alias_name)
150
+ end
151
+
152
+ ##
153
+ # Removes an alias for a function.
154
+ #
155
+ # *Arguments*
156
+ # [function_name] The lambda function name for which the alias should be removed.
157
+ # [alias_name] The alias to remove.
158
+ def remove_alias(function_name, alias_name)
159
+ @client.delete_alias(function_name: function_name, name: alias_name)
160
+ end
161
+
162
+ ##
163
+ # Adds permissions for API gateway to execute this function.
164
+ #
165
+ # *Arguments*
166
+ # [function_name] The function name which needs to be executed from API Gateway.
167
+ # [env] The environment (matching the function's alias) which needs to be executed from API Gateway.
168
+ # => If nil, the permissions are set of the $LATEST version.
169
+ def add_api_gateway_permissions(function_name, env)
170
+ # permissions to execute lambda
171
+ suffix = (':' + env if env) || ''
172
+ func = @client.get_function(function_name: function_name + suffix).data.configuration
173
+ statement_id = func.function_name + (('-' + env if env) || '')
174
+ begin
175
+ existing_policies = @client.get_policy(function_name: func.function_arn).data
176
+ existing_policy = JSON.parse(existing_policies.policy)
177
+ policy_exists = existing_policy['Statement'].select { |s| s['Sid'] == statement_id }.any?
178
+ rescue Aws::Lambda::Errors::ResourceNotFoundException
179
+ # policy does not exist, and that is ok
180
+ policy_exists = false
181
+ end
182
+
183
+ unless policy_exists
184
+ perm_add = @client.add_permission(
185
+ function_name: func.function_arn, statement_id: statement_id,
186
+ action: 'lambda:*', principal: 'apigateway.amazonaws.com'
187
+ )
188
+ puts perm_add.data
189
+ end
190
+ end
191
+
192
+ private :add_api_gateway_permissions
193
+ end
194
+ end
@@ -1,67 +1,67 @@
1
- require 'rubygems'
2
- require 'zip'
3
-
4
- module LambdaWrap
5
- ##
6
- # Allows to easily zip a directory recursively. It's intended for gem internal use only.
7
- #
8
- # From the original example:
9
- # This is a simple example which uses rubyzip to
10
- # recursively generate a zip file from the contents of
11
- # a specified directory. The directory itself is not
12
- # included in the archive, rather just its contents.
13
- #
14
- # Usage:
15
- # require /path/to/the/ZipFileGenerator/Class
16
- # directoryToZip = "/tmp/input"
17
- # outputFile = "/tmp/out.zip"
18
- # zf = ZipFileGenerator.new(directoryToZip, outputFile)
19
- # zf.write()
20
- class ZipFileGenerator
21
- ##
22
- # Initialize with the directory to zip and the location of the output archive.
23
- def initialize(input_dir, output_file)
24
- @input_dir = input_dir
25
- @output_file = output_file
26
- end
27
-
28
- ##
29
- # Zip the input directory.
30
- def write
31
- entries = Dir.entries(@input_dir) - %w(. ..)
32
-
33
- Zip::File.open(@output_file, Zip::File::CREATE) do |io|
34
- write_entries entries, '', io
35
- end
36
- end
37
-
38
- private
39
-
40
- # A helper method to make the recursion work.
41
- def write_entries(entries, path, io)
42
- entries.each do |e|
43
- zip_file_path = path == '' ? e : File.join(path, e)
44
- disk_file_path = File.join(@input_dir, zip_file_path)
45
- puts "Deflating #{disk_file_path}"
46
-
47
- if File.directory? disk_file_path
48
- recursively_deflate_directory(disk_file_path, io, zip_file_path)
49
- else
50
- put_into_archive(disk_file_path, io, zip_file_path)
51
- end
52
- end
53
- end
54
-
55
- def recursively_deflate_directory(disk_file_path, io, zip_file_path)
56
- io.mkdir zip_file_path
57
- subdir = Dir.entries(disk_file_path) - %w(. ..)
58
- write_entries subdir, zip_file_path, io
59
- end
60
-
61
- def put_into_archive(disk_file_path, io, zip_file_path)
62
- io.get_output_stream(zip_file_path) do |f|
63
- f.puts(File.open(disk_file_path, 'rb').read)
64
- end
65
- end
66
- end
67
- end
1
+ require 'rubygems'
2
+ require 'zip'
3
+
4
+ module LambdaWrap
5
+ ##
6
+ # Allows to easily zip a directory recursively. It's intended for gem internal use only.
7
+ #
8
+ # From the original example:
9
+ # This is a simple example which uses rubyzip to
10
+ # recursively generate a zip file from the contents of
11
+ # a specified directory. The directory itself is not
12
+ # included in the archive, rather just its contents.
13
+ #
14
+ # Usage:
15
+ # require /path/to/the/ZipFileGenerator/Class
16
+ # directoryToZip = "/tmp/input"
17
+ # outputFile = "/tmp/out.zip"
18
+ # zf = ZipFileGenerator.new(directoryToZip, outputFile)
19
+ # zf.write()
20
+ class ZipFileGenerator
21
+ ##
22
+ # Initialize with the directory to zip and the location of the output archive.
23
+ def initialize(input_dir, output_file)
24
+ @input_dir = input_dir
25
+ @output_file = output_file
26
+ end
27
+
28
+ ##
29
+ # Zip the input directory.
30
+ def write
31
+ entries = Dir.entries(@input_dir) - %w(. ..)
32
+
33
+ Zip::File.open(@output_file, Zip::File::CREATE) do |io|
34
+ write_entries entries, '', io
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # A helper method to make the recursion work.
41
+ def write_entries(entries, path, io)
42
+ entries.each do |e|
43
+ zip_file_path = path == '' ? e : File.join(path, e)
44
+ disk_file_path = File.join(@input_dir, zip_file_path)
45
+ puts "Deflating #{disk_file_path}"
46
+
47
+ if File.directory? disk_file_path
48
+ recursively_deflate_directory(disk_file_path, io, zip_file_path)
49
+ else
50
+ put_into_archive(disk_file_path, io, zip_file_path)
51
+ end
52
+ end
53
+ end
54
+
55
+ def recursively_deflate_directory(disk_file_path, io, zip_file_path)
56
+ io.mkdir zip_file_path
57
+ subdir = Dir.entries(disk_file_path) - %w(. ..)
58
+ write_entries subdir, zip_file_path, io
59
+ end
60
+
61
+ def put_into_archive(disk_file_path, io, zip_file_path)
62
+ io.get_output_stream(zip_file_path) do |f|
63
+ f.puts(File.open(disk_file_path, 'rb').read)
64
+ end
65
+ end
66
+ end
67
+ end
data/lib/lambda_wrap.rb CHANGED
@@ -1,5 +1,5 @@
1
- # :nodoc:
2
- Dir["#{File.expand_path(File.dirname(__FILE__))}/**/*.rb"].each { |f| require f }
3
-
4
- STDOUT.sync = true
5
- STDERR.sync = true
1
+ # :nodoc:
2
+ Dir["#{File.expand_path(File.dirname(__FILE__))}/**/*.rb"].each { |f| require f }
3
+
4
+ STDOUT.sync = true
5
+ 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.20.0
4
+ version: 0.21.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: 2016-10-07 00:00:00.000000000 Z
13
+ date: 2016-10-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: aws-sdk
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  version: '0'
74
74
  requirements: []
75
75
  rubyforge_project:
76
- rubygems_version: 2.6.7
76
+ rubygems_version: 2.2.5
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: Easy deployment of AWS Lambda functions and dependencies.