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.
@@ -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
- # 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
- # Updates the provisioned throughput read and write capacity of the requested table.
30
- # If the table does not exist an error message is displayed. If current read/write capacity
31
- # is equals to requested read/write capacity or the requested read/write capacity is 0 or less than 0
32
- # no table updation is performed.
33
- #
34
- # *Arguments*
35
- # [table_name] The table name of the dynamoDB to be updated.
36
- # [read_capacity] The read capacity the table should be updated with.
37
- # [write_capacity] The write capacity the table should be updated with.
38
- def update_table_capacity(table_name, read_capacity, write_capacity)
39
- # Check if table exists.
40
- begin
41
- table_details = @client.describe_table(table_name: table_name).table
42
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
43
- raise "Update cannot be performed. Table #{table_name} does not exists."
44
- end
45
-
46
- if (read_capacity <= 0 || write_capacity <= 0)
47
- puts "Table: #{table_name} not updated. Read/Write capacity should be greater than or equal to 1."
48
- elsif (read_capacity == table_details.provisioned_throughput.read_capacity_units ||
49
- write_capacity == table_details.provisioned_throughput.write_capacity_units)
50
- puts "Table: #{table_name} not updated. Current and requested reads/writes are same.
51
- Current ReadCapacityUnits provisioned for the table: #{table_details.provisioned_throughput.read_capacity_units}.
52
- Requested ReadCapacityUnits: #{read_capacity}.
53
- Current WriteCapacityUnits provisioned for the table: #{table_details.provisioned_throughput.write_capacity_units}.
54
- Requested WriteCapacityUnits: #{write_capacity}. "
55
- else
56
- response = @client.update_table(
57
- table_name: table_name,
58
- provisioned_throughput: { read_capacity_units: read_capacity, write_capacity_units: write_capacity })
59
-
60
- raise "Read and writes capacities was not updated for table: #{table_name}." unless (response.table_description.provisioned_throughput.read_capacity_units!= read_capacity ||
61
- response.table_description.provisioned_throughput.write_capacity_units!= write_capacity)
62
-
63
- puts "Updated new read/write capacity for table #{table_name}.
64
- Read capacity updated to: #{read_capacity}.
65
- Write capacity updated to: #{write_capacity}."
66
- end
67
- end
68
-
69
- ##
70
- # Publishes the database and awaits until it is fully available. If the table already exists,
71
- # it only adjusts the read and write
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] 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
- # figure out whether the table exists
90
- begin
91
- table_details = @client.describe_table(table_name: table_name).table
92
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
93
- # skip this exception because we are using it for control flow.
94
- table_details = nil
95
- end
96
-
97
- if table_details
98
- wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
99
-
100
- if read_capacity > table_details.provisioned_throughput.read_capacity_units ||
101
- write_capacity > table_details.provisioned_throughput.write_capacity_units
102
-
103
- set_table_capacity read_capacity, write_capacity
104
- has_updates = true
105
- else
106
- puts "Table #{table_name} already exists and the desired read capacity of #{read_capacity} and " \
107
- "write capacity of #{write_capacity} has at least been configured. Downgrading capacity units is not " \
108
- 'supported. No changes were applied.'
109
- end
110
- else
111
- puts "Creating table #{table_name}."
112
- ad = attribute_definitions || [{ attribute_name: 'Id', attribute_type: 'S' }]
113
- ks = key_schema || [{ attribute_name: 'Id', key_type: 'HASH' }]
114
-
115
- params = {
116
- table_name: table_name, key_schema: ks, attribute_definitions: ad,
117
- provisioned_throughput: {
118
- read_capacity_units: read_capacity, write_capacity_units: write_capacity
119
- }
120
- }
121
-
122
- params[:local_secondary_indexes] = local_secondary_indexes if local_secondary_indexes != nil
123
- params[:global_secondary_indexes] = global_secondary_indexes if global_secondary_indexes != nil
124
-
125
- @client.create_table(params)
126
- has_updates = true
127
- end
128
-
129
- if has_updates
130
- wait_until_table_available(table_name)
131
- puts "DynamoDB table #{table_name} is now fully available."
132
- end
133
- end
134
-
135
- ##
136
- # Deletes a DynamoDB table. It does not wait until the table has been deleted.
137
- #
138
- # *Arguments*
139
- # [table_name] The dynamoDB table name to delete.
140
- def delete_database(table_name)
141
- table_details = @client.describe_table(table_name: table_name).table
142
- wait_until_table_available(table_name) if table_details.table_status != 'ACTIVE'
143
- @client.delete_table(table_name: table_name)
144
- rescue Aws::DynamoDB::Errors::ResourceNotFoundException
145
- puts 'Table did not exist. Nothing to delete.'
146
- end
147
-
148
- ##
149
- # Awaits a given status of a table.
150
- #
151
- # *Arguments*
152
- # [table_name] The dynamoDB table name to watch until it reaches an active status.
153
- def wait_until_table_available(table_name)
154
- max_attempts = 24
155
- delay_between_attempts = 5
156
-
157
- # wait until the table has updated to being fully available
158
- # waiting for ~2min at most; an error will be thrown afterwards
159
- begin
160
- @client.wait_until(:table_exists, table_name: table_name) do |w|
161
- w.max_attempts = max_attempts
162
- w.delay = delay_between_attempts
163
- w.before_wait do |attempts, _|
164
- puts "Waiting until table becomes available. Attempt #{attempts}/#{max_attempts} " \
165
- "with polling interval #{delay_between_attempts}."
166
- end
167
- end
168
- rescue Aws::Waiters::Errors::TooManyAttemptsError => e
169
- puts "Table #{table_name} did not become available after #{e.attempts} attempts. " \
170
- 'Try again later or inspect the AWS console.'
171
- end
172
- end
173
-
174
- private :wait_until_table_available
175
- end
176
- 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
+ @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