lambda_wrap 0.26.0 → 0.26.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lambda_wrap/api_gateway_manager.rb +180 -180
- data/lib/lambda_wrap/dynamo_db_manager.rb +181 -176
- data/lib/lambda_wrap/lambda_manager.rb +208 -196
- data/lib/lambda_wrap/s3_bucket_manager.rb +5 -8
- data/lib/lambda_wrap/version.rb +3 -0
- data/lib/lambda_wrap/zip_file_generator.rb +67 -67
- data/lib/lambda_wrap.rb +5 -5
- metadata +9 -6
@@ -1,176 +1,181 @@
|
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# [
|
36
|
-
# [
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
puts "Table: #{table_name} not updated.
|
48
|
-
|
49
|
-
|
50
|
-
puts "
|
51
|
-
Current
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
# it
|
72
|
-
# capacities upwards (it doesn't downgrade them to avoid a production environment being impacted with
|
73
|
-
# a default setting of an automated script).
|
74
|
-
#
|
75
|
-
# *Arguments*
|
76
|
-
# [table_name]
|
77
|
-
# [attribute_definitions] The dynamoDB attribute definitions to be used when the table is created.
|
78
|
-
# [key_schema]
|
79
|
-
# [read_capacity]
|
80
|
-
# [write_capacity]
|
81
|
-
# [local_secondary_indexes]
|
82
|
-
# [global_secondary_indexes]
|
83
|
-
def publish_database(
|
84
|
-
table_name, attribute_definitions, key_schema, read_capacity, write_capacity, local_secondary_indexes = nil,
|
85
|
-
global_secondary_indexes = nil
|
86
|
-
)
|
87
|
-
has_updates = false
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
table_details
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
params =
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
+
@client = Aws::DynamoDB::Client.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_table_capacity(table_name, read_capacity, write_capacity)
|
18
|
+
puts "Updating new read/write capacity for table #{table_name}.
|
19
|
+
Read #{table_details.provisioned_throughput.read_capacity_units} ==> #{read_capacity}.
|
20
|
+
Write #{table_details.provisioned_throughput.write_capacity_units} ==> #{write_capacity}."
|
21
|
+
@client.update_table(
|
22
|
+
table_name: table_name,
|
23
|
+
provisioned_throughput: { read_capacity_units: read_capacity, write_capacity_units: write_capacity }
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Updates the provisioned throughput read and write capacity of the requested table.
|
29
|
+
# If the table does not exist an error message is displayed. If current read/write capacity
|
30
|
+
# is equals to requested read/write capacity or the requested read/write capacity is 0 or less than 0
|
31
|
+
# no table updation is performed.
|
32
|
+
#
|
33
|
+
# *Arguments*
|
34
|
+
# [table_name] The table name of the dynamoDB to be updated.
|
35
|
+
# [read_capacity] The read capacity the table should be updated with.
|
36
|
+
# [write_capacity] The write capacity the table should be updated with.
|
37
|
+
def update_table_capacity(table_name, read_capacity, write_capacity)
|
38
|
+
table_details = get_table_details(table_name)
|
39
|
+
raise "Update cannot be performed. Table #{table_name} does not exists." if table_details.nil?
|
40
|
+
|
41
|
+
wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
|
42
|
+
|
43
|
+
if read_capacity <= 0 || write_capacity <= 0
|
44
|
+
puts "Table: #{table_name} not updated. Read/Write capacity should be greater than or equal to 1."
|
45
|
+
elsif read_capacity == table_details.provisioned_throughput.read_capacity_units ||
|
46
|
+
write_capacity == table_details.provisioned_throughput.write_capacity_units
|
47
|
+
puts "Table: #{table_name} not updated. Current and requested reads/writes are same."
|
48
|
+
puts 'Current ReadCapacityUnits provisioned for the table: ' \
|
49
|
+
"#{table_details.provisioned_throughput.read_capacity_units}."
|
50
|
+
puts "Requested ReadCapacityUnits: #{read_capacity}."
|
51
|
+
puts 'Current WriteCapacityUnits provisioned for the table: ' \
|
52
|
+
"#{table_details.provisioned_throughput.write_capacity_units}."
|
53
|
+
puts "Requested WriteCapacityUnits: #{write_capacity}."
|
54
|
+
else
|
55
|
+
response = @client.update_table(
|
56
|
+
table_name: table_name,
|
57
|
+
provisioned_throughput: { read_capacity_units: read_capacity, write_capacity_units: write_capacity }
|
58
|
+
)
|
59
|
+
|
60
|
+
if response.table_description.table_status == 'UPDATING'
|
61
|
+
puts "Updated new read/write capacity for table #{table_name}.
|
62
|
+
Read capacity updated to: #{read_capacity}.
|
63
|
+
Write capacity updated to: #{write_capacity}."
|
64
|
+
else
|
65
|
+
raise "Read and writes capacities was not updated for table: #{table_name}."
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Publishes the database and awaits until it is fully available. If the table already exists, it only adjusts the
|
72
|
+
# read and write capacities upwards (it doesn't downgrade them to avoid a production environment being impacted with
|
73
|
+
# a default setting of an automated script).
|
74
|
+
#
|
75
|
+
# *Arguments*
|
76
|
+
# [table_name] The table name of the dynamoDB to be created.
|
77
|
+
# [attribute_definitions] The dynamoDB attribute definitions to be used when the table is created.
|
78
|
+
# [key_schema] The dynamoDB key definitions to be used when the table is created.
|
79
|
+
# [read_capacity] The read capacity to configure for the dynamoDB table.
|
80
|
+
# [write_capacity] The write capacity to configure for the dynamoDB table.
|
81
|
+
# [local_secondary_indexes] The local secondary indexes to be created.
|
82
|
+
# [global_secondary_indexes] The global secondary indexes to be created.
|
83
|
+
def publish_database(
|
84
|
+
table_name, attribute_definitions, key_schema, read_capacity, write_capacity, local_secondary_indexes = nil,
|
85
|
+
global_secondary_indexes = nil
|
86
|
+
)
|
87
|
+
has_updates = false
|
88
|
+
|
89
|
+
table_details = get_table_details(table_name)
|
90
|
+
|
91
|
+
if !table_details.nil?
|
92
|
+
wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
|
93
|
+
|
94
|
+
if read_capacity > table_details.provisioned_throughput.read_capacity_units ||
|
95
|
+
write_capacity > table_details.provisioned_throughput.write_capacity_units
|
96
|
+
set_table_capacity(read_capacity, write_capacity)
|
97
|
+
has_updates = true
|
98
|
+
else
|
99
|
+
puts "Table #{table_name} already exists and the desired read capacity of #{read_capacity} and " \
|
100
|
+
"write capacity of #{write_capacity} has at least been configured. Downgrading capacity units is not " \
|
101
|
+
'supported. No changes were applied.'
|
102
|
+
end
|
103
|
+
else
|
104
|
+
puts "Creating table #{table_name}."
|
105
|
+
ad = attribute_definitions || [{ attribute_name: 'Id', attribute_type: 'S' }]
|
106
|
+
ks = key_schema || [{ attribute_name: 'Id', key_type: 'HASH' }]
|
107
|
+
|
108
|
+
params = {
|
109
|
+
table_name: table_name, key_schema: ks, attribute_definitions: ad,
|
110
|
+
provisioned_throughput: {
|
111
|
+
read_capacity_units: read_capacity, write_capacity_units: write_capacity
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
params[:local_secondary_indexes] = local_secondary_indexes unless local_secondary_indexes.nil?
|
116
|
+
params[:global_secondary_indexes] = global_secondary_indexes unless global_secondary_indexes.nil?
|
117
|
+
|
118
|
+
@client.create_table(params)
|
119
|
+
has_updates = true
|
120
|
+
end
|
121
|
+
|
122
|
+
if has_updates
|
123
|
+
wait_until_table_available(table_name)
|
124
|
+
puts "DynamoDB table #{table_name} is now fully available."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Deletes a DynamoDB table. It does not wait until the table has been deleted.
|
130
|
+
#
|
131
|
+
# *Arguments*
|
132
|
+
# [table_name] The dynamoDB table name to delete.
|
133
|
+
def delete_database(table_name)
|
134
|
+
table_details = get_table_details(table_name)
|
135
|
+
if table_details.nil?
|
136
|
+
puts 'Table did not exist. Nothing to delete.'
|
137
|
+
else
|
138
|
+
wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
|
139
|
+
@client.delete_table(table_name: table_name)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Awaits a given status of a table.
|
145
|
+
#
|
146
|
+
# *Arguments*
|
147
|
+
# [table_name] The dynamoDB table name to watch until it reaches an active status.
|
148
|
+
def wait_until_table_available(table_name)
|
149
|
+
max_attempts = 24
|
150
|
+
delay_between_attempts = 5
|
151
|
+
|
152
|
+
# wait until the table has updated to being fully available
|
153
|
+
# waiting for ~2min at most; an error will be thrown afterwards
|
154
|
+
begin
|
155
|
+
@client.wait_until(:table_exists, table_name: table_name) do |w|
|
156
|
+
w.max_attempts = max_attempts
|
157
|
+
w.delay = delay_between_attempts
|
158
|
+
w.before_wait do |attempts, _|
|
159
|
+
puts "Waiting until table becomes available. Attempt #{attempts}/#{max_attempts} " \
|
160
|
+
"with polling interval #{delay_between_attempts}."
|
161
|
+
end
|
162
|
+
end
|
163
|
+
rescue Aws::Waiters::Errors::TooManyAttemptsError => e
|
164
|
+
puts "Table #{table_name} did not become available after #{e.attempts} attempts. " \
|
165
|
+
'Try again later or inspect the AWS console.'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def get_table_details(table_name)
|
170
|
+
table_details = nil
|
171
|
+
begin
|
172
|
+
table_details = @client.describe_table(table_name: table_name).table
|
173
|
+
rescue Aws::DynamoDB::Errors::ResourceNotFoundException
|
174
|
+
puts "Table #{table_name} does not exist."
|
175
|
+
end
|
176
|
+
table_details
|
177
|
+
end
|
178
|
+
|
179
|
+
private :wait_until_table_available, :get_table_details
|
180
|
+
end
|
181
|
+
end
|