lambda_wrap 0.19.0 → 0.20.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: 0e51edbb1fbe30b3c7f2a6966803035be85a0eed
4
- data.tar.gz: 0f18904aea22e7c7526ab9499fed608b836d81e0
3
+ metadata.gz: 967cbf57b49c5c9089d2b7fb499e918e06b0c2cd
4
+ data.tar.gz: e04be077d970608457c40613e8c42cb41364822f
5
5
  SHA512:
6
- metadata.gz: 6a53810ab4ec845226795c77a097f911adeebd06704a9864e1499ab690ff964dde81401d21ece9edad2a78a29ccf1c5f5329c7cdd849c716c3669e9f331be4b3
7
- data.tar.gz: 809a4b65ef87718777b00f2df87f1948ab1feacd13e9c1f349b7e21ad1dfe95df709ea260d3093fb6b1cfacfe6236773ece85adb7ae2208a48a0ec13bbd03b97
6
+ metadata.gz: ce0921cb5e342d7b6dee2caec10bc1c0f7ac73f240f3fd3a8afd0dff72cf7137bdd1b0203871713eac296384352a095c59fdd4a2857cd751d466dbb5f293bfe7
7
+ data.tar.gz: 722c438455fc50aabdb5528ee568679f6920aef78291591ae9b249c785f1ff09dd2989e754b5ca684443fb0f5cb2141704236e6faadca3887570edbe231f58ec
@@ -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,182 +1,188 @@
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
- func_version = func_config.version
91
- raise 'Error while publishing existing lambda function ' + function_name unless func_version
92
- rescue Aws::Lambda::Errors::ResourceNotFoundException
93
- # check if vpc_subnet_ids and vpc_security_group_ids are empty or not and set the vpc_config accordingly.
94
- vpc_Configuration = nil
95
- vpc_Configuration = { subnet_ids: vpc_subnet_ids, security_group_ids: vpc_security_group_ids } unless (vpc_subnet_ids.empty? && vpc_security_group_ids.empty?)
96
-
97
- # if we cannot find it, we have to create it instead of updating it
98
- func_config = @client.create_function(
99
- function_name: function_name, runtime: runtime, role: lambda_role,
100
- handler: handler, code: { s3_bucket: bucket, s3_key: key }, timeout: 5, memory_size: 128, publish: true,
101
- description: lambda_description,
102
- vpc_config: vpc_Configuration
103
- ).data
104
- puts func_config
105
- func_version = func_config.version
106
- raise "Error while publishing new lambda function #{function_name}" unless func_version
107
- end
108
-
109
- add_api_gateway_permissions(function_name, nil)
110
-
111
- func_version
112
- end
113
-
114
- ##
115
- # Creates an alias for a given lambda function version.
116
- #
117
- # *Arguments*
118
- # [function_name] The lambda function name for which the alias should be created.
119
- # [func_version] The lambda function versino to which the alias should point.
120
- # [alias_name] The name of the alias, matching the LambdaWrap environment concept.
121
- def create_alias(function_name, func_version, alias_name)
122
- # create or update alias
123
- func_alias = @client.list_aliases(function_name: function_name).aliases.select { |a| a.name == alias_name }.first
124
- if !func_alias
125
- a = @client.create_alias(
126
- function_name: function_name, name: alias_name, function_version: func_version,
127
- description: 'created by an automated script'
128
- ).data
129
- else
130
- a = @client.update_alias(
131
- function_name: function_name, name: alias_name, function_version: func_version,
132
- description: 'updated by an automated script'
133
- ).data
134
- end
135
- puts a
136
-
137
- add_api_gateway_permissions(function_name, alias_name)
138
- end
139
-
140
- ##
141
- # Removes an alias for a function.
142
- #
143
- # *Arguments*
144
- # [function_name] The lambda function name for which the alias should be removed.
145
- # [alias_name] The alias to remove.
146
- def remove_alias(function_name, alias_name)
147
- @client.delete_alias(function_name: function_name, name: alias_name)
148
- end
149
-
150
- ##
151
- # Adds permissions for API gateway to execute this function.
152
- #
153
- # *Arguments*
154
- # [function_name] The function name which needs to be executed from API Gateway.
155
- # [env] The environment (matching the function's alias) which needs to be executed from API Gateway.
156
- # => If nil, the permissions are set of the $LATEST version.
157
- def add_api_gateway_permissions(function_name, env)
158
- # permissions to execute lambda
159
- suffix = (':' + env if env) || ''
160
- func = @client.get_function(function_name: function_name + suffix).data.configuration
161
- statement_id = func.function_name + (('-' + env if env) || '')
162
- begin
163
- existing_policies = @client.get_policy(function_name: func.function_arn).data
164
- existing_policy = JSON.parse(existing_policies.policy)
165
- policy_exists = existing_policy['Statement'].select { |s| s['Sid'] == statement_id }.any?
166
- rescue Aws::Lambda::Errors::ResourceNotFoundException
167
- # policy does not exist, and that is ok
168
- policy_exists = false
169
- end
170
-
171
- unless policy_exists
172
- perm_add = @client.add_permission(
173
- function_name: func.function_arn, statement_id: statement_id,
174
- action: 'lambda:*', principal: 'apigateway.amazonaws.com'
175
- )
176
- puts perm_add.data
177
- end
178
- end
179
-
180
- private :add_api_gateway_permissions
181
- end
182
- 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
+ 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,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.19.0
4
+ version: 0.20.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-09-06 00:00:00.000000000 Z
13
+ date: 2016-10-07 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.2.5
76
+ rubygems_version: 2.6.7
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: Easy deployment of AWS Lambda functions and dependencies.