cfn_manage 0.1.3 → 0.2.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: 0f48d15f16f01693d8136bb57cdf406bfe9dca26
4
- data.tar.gz: 383c8c152a7a40748991ffdc79f89006a2c336df
3
+ metadata.gz: 69073fce6ae1e187369356d37b9180d21560b3de
4
+ data.tar.gz: 4d73c20f1873ec4abab56bf6b82bf429b6920995
5
5
  SHA512:
6
- metadata.gz: 3e4561f755c74c856c69054a20ce3e5850a51ce4cb78136d849e46ec7d634cf6568923bd5c943cefe4c5394840f02d195ca8e8f74e732cb5c31ccbfd0d976613
7
- data.tar.gz: 0a6dddd09ac36177ee2261eba24cecb455b8d1489f370f0c205c0c9d13d59b23c7a7f22841510613eeb0a1930eadaf214b0935b4296cfa084aa2a7d6a4317784
6
+ metadata.gz: 78e8e4f22bbc90e8ff23a6f9c0a521c5ef58085856ca85eccf8f52e8903b8121251105673d2e959a431be3d8eac9cb7ba0a46d3aa8dcf719948d8565f4f59c9b
7
+ data.tar.gz: c6fa186c4c1c14b39d54febf5c36b7e316b20ae2ed61e31da2aee16c7b5a2fbf0ae079a6d11447e06e5eefb198cb26952d05de98842f314a67ed9fa49bcada02
@@ -0,0 +1,39 @@
1
+ require_relative '../lib/aws_credentials'
2
+
3
+ module Base2
4
+
5
+ class AlarmStartStopHandler
6
+
7
+ def initialize(alarm_name)
8
+ @alarm_id = alarm_name
9
+ credentials = Base2::AWSCredentials.get_session_credentials("startstopalarm_#{@asg_name}")
10
+ @cwclient = Aws::CloudWatch::Client.new()
11
+ if credentials != nil
12
+ @cwclient = Aws::CloudWatch::Client.new(credentials: credentials)
13
+ end
14
+
15
+ @cwresource = Aws::CloudWatch::Resource.new(client: @cwclient)
16
+ @alarm = @cwresource.alarm(alarm_name)
17
+ end
18
+
19
+ def start(configuration)
20
+ if @alarm.actions_enabled
21
+ $log.info("Alarm #{@alarm.alarm_arn} actions already enabled")
22
+ return
23
+ end
24
+ $log.info("Enabling alarm #{@alarm.alarm_arn}")
25
+ @alarm.enable_actions({})
26
+ end
27
+
28
+ def stop
29
+ if not @alarm.actions_enabled
30
+ $log.info("Alarm #{@alarm.alarm_arn} actions already disabled")
31
+ return {}
32
+ end
33
+ $log.info("Disabling actions on alarm #{@alarm.alarm_arn}")
34
+ @alarm.disable_actions({})
35
+ return {}
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,70 @@
1
+ require_relative '../lib/aws_credentials'
2
+
3
+ module Base2
4
+
5
+ class AsgStartStopHandler
6
+
7
+ def initialize(asg_id)
8
+ @asg_name = asg_id
9
+
10
+ credentials = Base2::AWSCredentials.get_session_credentials("stopasg_#{@asg_name}")
11
+ @asg_client = Aws::AutoScaling::Client.new()
12
+ if credentials != nil
13
+ @asg_client = Aws::AutoScaling::Client.new(credentials: credentials)
14
+ end
15
+
16
+ asg_details = @asg_client.describe_auto_scaling_groups(
17
+ auto_scaling_group_names: [@asg_name]
18
+ )
19
+ if asg_details.auto_scaling_groups.size() == 0
20
+ raise "Couldn't find ASG #{@asg_name}"
21
+ end
22
+ @asg = asg_details.auto_scaling_groups[0]
23
+ end
24
+
25
+ def stop
26
+ # check if already stopped
27
+ if @asg.min_size == @asg.max_size and @asg.max_size == @asg.desired_capacity and @asg.min_size == 0
28
+ $log.info("ASG #{@asg_name} already stopped")
29
+ # nil and false configurations are not saved
30
+ return nil
31
+ else
32
+ # store asg configuration to S3
33
+ configuration = {
34
+ desired_capacity: @asg.desired_capacity,
35
+ min_size: @asg.min_size,
36
+ max_size: @asg.max_size
37
+ }
38
+
39
+ $log.info("Setting desired capacity to 0/0/0 for ASG #{@asg.auto_scaling_group_name}A")
40
+ # set asg configuration to 0/0/0
41
+ puts @asg.auto_scaling_group_name
42
+ @asg_client.update_auto_scaling_group({
43
+ auto_scaling_group_name: "#{@asg.auto_scaling_group_name}",
44
+ min_size: 0,
45
+ max_size: 0,
46
+ desired_capacity: 0
47
+ })
48
+ return configuration
49
+ end
50
+
51
+ end
52
+
53
+ def start(configuration)
54
+ if configuration.nil?
55
+ $log.warn("No configuration found for #{@asg_name}, skipping..")
56
+ return
57
+ end
58
+ $log.info("Starting ASG #{@asg_name} with following configuration\n#{configuration}")
59
+
60
+ # restore asg sizes
61
+ @asg_client.update_auto_scaling_group({
62
+ auto_scaling_group_name: @asg_name,
63
+ min_size: configuration['min_size'],
64
+ max_size: configuration['max_size'],
65
+ desired_capacity: configuration['desired_capacity']
66
+ })
67
+ end
68
+
69
+ end
70
+ end
@@ -3,6 +3,7 @@ require_relative '../lib/cf_common'
3
3
  require_relative '../lib/aws_credentials'
4
4
  require 'json'
5
5
  require 'yaml'
6
+ require_relative '../lib/start_stop_handler_factory'
6
7
 
7
8
  module Base2
8
9
  module CloudFormation
@@ -14,20 +15,14 @@ module Base2
14
15
  @s3_bucket = nil
15
16
  @credentials = nil
16
17
  @dry_run = false
17
- @@supported_start_stop_resources = {
18
- 'AWS::AutoScaling::AutoScalingGroup' => 'start_stop_asg',
19
- 'AWS::RDS::DBInstance' => 'start_stop_rds',
20
- 'AWS::EC2::Instance' => 'start_stop_ec2'
21
- }
22
18
 
23
19
  @@resource_start_priorities = {
24
20
  'AWS::RDS::DBInstance' => '100',
25
21
  'AWS::AutoScaling::AutoScalingGroup' => '200',
26
- 'AWS::EC2::Instance' => '200'
22
+ 'AWS::EC2::Instance' => '200',
23
+ 'AWS::CloudWatch::Alarm' => '300'
27
24
  }
28
25
 
29
- @environment_resources = nil
30
-
31
26
  def initialize()
32
27
  @environment_resources = []
33
28
  @s3_client = Aws::S3::Client.new()
@@ -35,7 +30,7 @@ module Base2
35
30
  @cf_client = Aws::CloudFormation::Client.new()
36
31
  @credentials = Base2::AWSCredentials.get_session_credentials('start_stop_environment')
37
32
  if not @credentials.nil?
38
- @cf_client = Aws::CloudFormation::Client.new(credentials: @credentials)
33
+ @cf_client = Aws::CloudFormation::Client.new(credentials: @credentials)
39
34
  end
40
35
  @dry_run = (ENV.key?('DRY_RUN') and ENV['DRY_RUN'] == '1')
41
36
  end
@@ -45,7 +40,7 @@ module Base2
45
40
  $log.info("Starting environment #{stack_name}")
46
41
  Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
47
42
  do_start_assets
48
- configuration = {stack_running: true}
43
+ configuration = { stack_running: true }
49
44
  save_item_configuration("environment-data/stack-data/#{stack_name}", configuration) unless @dry_run
50
45
  $log.info("Environment #{stack_name} started")
51
46
  end
@@ -55,7 +50,7 @@ module Base2
55
50
  $log.info("Stopping environment #{stack_name}")
56
51
  Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
57
52
  do_stop_assets
58
- configuration = {stack_running: false}
53
+ configuration = { stack_running: false }
59
54
  save_item_configuration("environment-data/stack-data/#{stack_name}", configuration) unless @dry_run
60
55
  $log.info("Environment #{stack_name} stopped")
61
56
  end
@@ -63,13 +58,17 @@ module Base2
63
58
 
64
59
  def do_stop_assets
65
60
  # sort start resource by priority
66
- @environment_resources = @environment_resources.sort_by { |k| k[:priority]}.reverse
61
+ @environment_resources = @environment_resources.sort_by { |k| k[:priority] }.reverse
67
62
 
68
63
  @environment_resources.each do |resource|
69
64
  $log.info("Stopping resource #{resource[:id]}")
70
65
  # just print out information if running a dry run, otherwise start assets
71
66
  if not @dry_run
72
- eval "self.#{resource[:method]}('stop','#{resource[:id]}')"
67
+ configuration = resource[:handler].stop()
68
+ if configuration.class == Hash
69
+ s3_prefix = "environment_data/resource/#{resource[:id]}"
70
+ save_item_configuration(s3_prefix, configuration)
71
+ end
73
72
  else
74
73
  $log.info("Dry run enabled, skipping stop start\nFollowing resource would be stopped: #{resource[:id]}")
75
74
  $log.debug("Resource type: #{resource[:type]}\n\n")
@@ -77,16 +76,20 @@ module Base2
77
76
  end
78
77
  end
79
78
 
80
-
81
79
  def do_start_assets
82
80
  # sort start resource by priority
83
- @environment_resources = @environment_resources.sort_by { |k| k[:priority]}
81
+ @environment_resources = @environment_resources.sort_by { |k| k[:priority] }
84
82
 
85
83
  @environment_resources.each do |resource|
86
84
  $log.info("Starting resource #{resource[:id]}")
87
85
  # just print out information if running a dry run, otherwise start assets
88
86
  if not @dry_run
89
- eval "self.#{resource[:method]}('start','#{resource[:id]}')"
87
+ # read configuration
88
+ s3_prefix = "environment_data/resource/#{resource[:id]}"
89
+ configuration = get_object_configuration(s3_prefix)
90
+
91
+ # start
92
+ resource[:handler].start(configuration)
90
93
  else
91
94
  $log.info("Dry run enabled, skipping actual start\nFollowing resource would be started: #{resource[:id]}")
92
95
  $log.debug("Resource type: #{resource[:type]}\n\n")
@@ -97,235 +100,28 @@ module Base2
97
100
  def collect_resources(stack_name)
98
101
  resrouces = @cf_client.describe_stack_resources(stack_name: stack_name)
99
102
  resrouces['stack_resources'].each do |resource|
100
- if @@supported_start_stop_resources.key?(resource['resource_type'])
101
- method_name = @@supported_start_stop_resources[resource['resource_type']]
103
+ start_stop_handler = nil
104
+ begin
105
+ start_stop_handler = Base2::StartStopHandlerFactory.get_start_stop_handler(
106
+ resource['resource_type'],
107
+ resource['physical_resource_id']
108
+ )
109
+ rescue Exception => e
110
+ $log.error("Error creating start-stop handler for resource of type #{resource['resource_type']}" +
111
+ "and with id #{resource['physical_resource_id']}:#{e}")
112
+ end
113
+ if not start_stop_handler.nil?
102
114
  resource_id = resource['physical_resource_id']
103
-
104
115
  @environment_resources << {
105
116
  id: resource_id,
106
117
  priority: @@resource_start_priorities[resource['resource_type']],
107
- method: method_name,
118
+ handler: start_stop_handler,
108
119
  type: resource['resource_type']
109
120
  }
110
121
  end
111
122
  end
112
123
  end
113
124
 
114
- def start_stop_ec2(cmd, instance_id)
115
- credentials = Base2::AWSCredentials.get_session_credentials("stoprun_#{instance_id}")
116
- ec2_client = Aws::EC2::Client.new(credentials: credentials)
117
-
118
- begin
119
- instance = Aws::EC2::Resource.new(client: ec2_client).instance(instance_id)
120
-
121
- if cmd == 'stop'
122
- if %w(stopped stopping).include?(instance.state.name)
123
- $log.info("Instance #{instance_id} already stopping or stopped")
124
- return
125
- end
126
- $log.info("Stopping instance #{instance_id}")
127
- instance.stop()
128
- end
129
-
130
- if cmd == 'start'
131
- if %w(running).include?(instance.state.name)
132
- $log.info("Instance #{instance_id} already running")
133
- return
134
- end
135
- $log.info("Starting instance #{instance_id}")
136
- instance.start()
137
- end
138
- rescue => e
139
- $log.error("Failed execution #{cmd} on instance #{instance_id}:\n#{e}")
140
- end
141
-
142
- end
143
-
144
- def start_stop_asg(cmd, asg_name)
145
-
146
- # read asg data
147
- credentials = Base2::AWSCredentials.get_session_credentials("stopasg_#{asg_name}")
148
- asg_client = Aws::AutoScaling::Client.new()
149
- if credentials != nil
150
- asg_client = Aws::AutoScaling::Client.new(credentials: credentials)
151
- end
152
-
153
- asg_details = asg_client.describe_auto_scaling_groups(
154
- auto_scaling_group_names: [asg_name]
155
- )
156
- if asg_details.auto_scaling_groups.size() == 0
157
- raise "Couldn't find ASG #{asg_name}"
158
- end
159
- asg = asg_details.auto_scaling_groups[0]
160
- s3_prefix = "environment-data/asg-data/#{asg_name}"
161
- case cmd
162
- when 'start'
163
-
164
- # retrieve asg params from s3
165
- configuration = self.get_object_configuration(s3_prefix)
166
- if configuration.nil?
167
- $log.warn("No configuration found for #{asg_name}, skipping..")
168
- return
169
- end
170
- $log.info("Starting ASG #{asg_name} with following configuration\n#{configuration}")
171
-
172
- # restore asg sizes
173
- asg_client.update_auto_scaling_group({
174
- auto_scaling_group_name: asg_name,
175
- min_size: configuration['min_size'],
176
- max_size: configuration['max_size'],
177
- desired_capacity: configuration['desired_capacity']
178
- })
179
-
180
- when 'stop'
181
- # check if already stopped
182
- if asg.min_size == asg.max_size and asg.max_size == asg.desired_capacity and asg.min_size == 0
183
- $log.info("ASG #{asg_name} already stopped")
184
- else
185
- # store asg configuration to S3
186
- configuration = {
187
- desired_capacity: asg.desired_capacity,
188
- min_size: asg.min_size,
189
- max_size: asg.max_size
190
- }
191
- self.save_item_configuration(s3_prefix, configuration)
192
-
193
- $log.info("Setting desired capacity to 0/0/0 for ASG #{asg_name}")
194
- # set asg configuration to 0/0/0
195
- asg_client.update_auto_scaling_group({
196
- auto_scaling_group_name: asg_name,
197
- min_size: 0,
198
- max_size: 0,
199
- desired_capacity: 0
200
- })
201
- end
202
- # TODO wait for operation to complete (optionally)
203
- end
204
-
205
-
206
- end
207
-
208
- def start_stop_rds(cmd, instance_id)
209
- credentials = Base2::AWSCredentials.get_session_credentials("startstoprds_#{instance_id}")
210
- rds_client = Aws::RDS::Client.new()
211
- if credentials != nil
212
- rds_client = Aws::RDS::Client.new(credentials: credentials)
213
- end
214
- rds = Aws::RDS::Resource.new(client: rds_client)
215
- rds_instance = rds.db_instance(instance_id)
216
- s3_prefix = "environment-data/rds-data/#{instance_id}"
217
- case cmd
218
- when 'start'
219
- if rds_instance.db_instance_status == 'available'
220
- $log.info("RDS Instance #{instance_id} is already in available state")
221
- return
222
- end
223
-
224
- #retrieve multi-az data from S3
225
- configuration = get_object_configuration(s3_prefix)
226
- if configuration.nil?
227
- $log.warning("No configuration found for #{rds_instance}, skipping..")
228
- return
229
- end
230
-
231
- # start rds instance
232
- if rds_instance.db_instance_status == 'stopped'
233
- $log.info("Starting db instance #{instance_id}")
234
- rds_client.start_db_instance({ db_instance_identifier: instance_id })
235
-
236
- # wait instance to become available
237
- $log.info("Waiting db instance to become available #{instance_id}")
238
- wait_rds_instance_states(rds_client, instance_id, %w(starting available))
239
- else
240
- wait_rds_instance_states(rds_client, instance_id, %w(available))
241
- end
242
-
243
- # convert rds instance to mutli-az if required
244
- if configuration['is_multi_az']
245
- $log.info("Converting to Multi-AZ instance after start (instance #{instance_id})")
246
- set_rds_instance_multi_az(rds_instance, true)
247
- end
248
-
249
- when 'stop'
250
- # store mutli-az data to S3
251
- if rds_instance.db_instance_status != 'available'
252
- $log.warn("RDS Instance #{instance_id} not in available state, and thus can not be stopped")
253
- $log.warn("RDS Instance #{instance_id} state: #{rds_instance.db_instance_status}")
254
- return
255
- end
256
-
257
- if rds_instance.db_instance_status == 'stopped'
258
- $log.info("RDS Instance #{instance_id} is already stopped")
259
- return
260
- end
261
-
262
- # RDS stop start does not support Aurora yet. Ignore if engine is aurora
263
- if rds_instance.engine == 'aurora'
264
- $log.info("RDS Instance #{instance_id} engine is aurora and cannot be stoped yet...")
265
- return
266
- end
267
-
268
- configuration = {
269
- is_multi_az: rds_instance.multi_az
270
- }
271
- save_item_configuration(s3_prefix, configuration)
272
-
273
- #check if mutli-az RDS. if so, convert to single-az
274
- if rds_instance.multi_az
275
- $log.info("Converting to Non-Multi-AZ instance before stop (instance #{instance_id}")
276
- set_rds_instance_multi_az(rds_instance, false)
277
- end
278
-
279
- # stop rds instance and wait for it to be fully stopped
280
- $log.info("Stopping instance #{instance_id}")
281
- rds_client.stop_db_instance({ db_instance_identifier: instance_id })
282
- $log.info("Waiting db instance to be stopped #{instance_id}")
283
- wait_rds_instance_states(rds_client, instance_id, %w(stopping stopped))
284
- end
285
- end
286
-
287
- def set_rds_instance_multi_az(rds_instance, multi_az)
288
- if rds_instance.multi_az == multi_az
289
- $log.info("Rds instance #{rds_instance.db_instance_identifier} already multi-az=#{multi_az}")
290
- return
291
- end
292
- rds_instance.modify({ multi_az: multi_az, apply_immediately: true })
293
- # allow half an hour for instance to be converted
294
- wait_states = %w(modifying available)
295
- wait_rds_instance_states(rds_instance, wait_states)
296
- end
297
-
298
- def wait_rds_instance_states(client, rds_instance_id, wait_states)
299
- wait_states.each do |state|
300
- # reached state must be steady, at least a minute. Modifying an instance to/from MultiAZ can't be shorter
301
- # than 40 seconds, hence steady count is 4
302
- state_count = 0
303
- steady_count = 4
304
- attempts = 0
305
- rds = Aws::RDS::Resource.new(client: client)
306
- until attempts == (max_attempts = 60*6) do
307
- instance = rds.db_instance(rds_instance_id)
308
- $log.info("Instance #{instance.db_instance_identifier} state: #{instance.db_instance_status}, waiting for #{state}")
309
-
310
- if instance.db_instance_status == "#{state}"
311
- state_count = state_count + 1
312
- $log.info("#{state_count}/#{steady_count}")
313
- else
314
- state_count = 0
315
- end
316
- break if state_count == steady_count
317
- attempts = attempts + 1
318
- sleep(15)
319
- end
320
-
321
- if attempts == max_attempts
322
- $log.error("RDS Database Instance #{rds_instance_id} did not enter #{state} state, however continuing operations...")
323
- end
324
-
325
- end
326
- end
327
-
328
-
329
125
  def get_object_configuration(s3_prefix)
330
126
  configuration = nil
331
127
  begin
@@ -358,6 +154,9 @@ module Base2
358
154
  })
359
155
  end
360
156
  end
157
+
158
+ private :do_stop_assets, :do_start_assets, :collect_resources, :get_object_configuration, :save_item_configuration
159
+
361
160
  end
362
161
  end
363
162
  end
@@ -0,0 +1,41 @@
1
+ require_relative '../lib/aws_credentials'
2
+
3
+ module Base2
4
+
5
+ class Ec2StartStopHandler
6
+
7
+ @instance
8
+
9
+ def initialize(instance_id)
10
+ credentials = Base2::AWSCredentials.get_session_credentials("stoprun_#{instance_id}")
11
+ ec2_client = Aws::EC2::Client.new(credentials: credentials)
12
+ @instance = Aws::EC2::Resource.new(client: ec2_client).instance(instance_id)
13
+ @instance_id = instance_id
14
+ end
15
+
16
+ def start(configuration)
17
+ if %w(running).include?(@instance.state.name)
18
+ $log.info("Instance #{@instance_id} already running")
19
+ return
20
+ end
21
+ $log.info("Starting instance #{@instance_id}")
22
+ @instance.start()
23
+ end
24
+
25
+ def stop
26
+ if %w(stopped stopping).include?(@instance.state.name)
27
+ $log.info("Instance #{@instance_id} already stopping or stopped")
28
+ return
29
+ end
30
+ $log.info("Stopping instance #{@instance_id}")
31
+ @instance.stop()
32
+
33
+ # empty configuration for ec2 instances
34
+ return {}
35
+ end
36
+
37
+
38
+
39
+
40
+ end
41
+ end
@@ -0,0 +1,128 @@
1
+ require_relative '../lib/aws_credentials'
2
+
3
+ module Base2
4
+
5
+ class RdsStartStopHandler
6
+
7
+ def initialize(instance_id)
8
+ @instance_id = instance_id
9
+
10
+ credentials = Base2::AWSCredentials.get_session_credentials("startstoprds_#{instance_id}")
11
+ @rds_client = Aws::RDS::Client.new()
12
+ if credentials != nil
13
+ @rds_client = Aws::RDS::Client.new(credentials: credentials)
14
+ end
15
+ rds = Aws::RDS::Resource.new(client: @rds_client)
16
+ @rds_instance = rds.db_instance(instance_id)
17
+
18
+ end
19
+
20
+ def start(configuration)
21
+ if @rds_instance.db_instance_status == 'available'
22
+ $log.info("RDS Instance #{@instance_id} is already in available state")
23
+ return
24
+ end
25
+
26
+ # start rds instance
27
+ if @rds_instance.db_instance_status == 'stopped'
28
+ $log.info("Starting db instance #{@instance_id}")
29
+ @rds_client.start_db_instance({ db_instance_identifier: @instance_id })
30
+
31
+ # wait instance to become available
32
+ $log.info("Waiting db instance to become available #{@instance_id}")
33
+ wait_rds_instance_states( %w(starting available))
34
+ else
35
+ wait_rds_instance_states( %w(available))
36
+ end
37
+
38
+ # convert rds instance to mutli-az if required
39
+ if configuration['is_multi_az']
40
+ $log.info("Converting to Multi-AZ instance after start (instance #{@instance_id})")
41
+ set_rds_instance_multi_az( true)
42
+ end
43
+ end
44
+
45
+ def stop
46
+
47
+ configuration = {
48
+ is_multi_az: @rds_instance.multi_az
49
+ }
50
+ # RDS stop start does not support Aurora yet. Ignore if engine is aurora
51
+ if @rds_instance.engine == 'aurora'
52
+ $log.info("RDS Instance #{instance_id} engine is aurora and cannot be stoped yet...")
53
+ return configuration
54
+ end
55
+
56
+ # check if available
57
+ if @rds_instance.db_instance_status != 'available'
58
+ $log.warn("RDS Instance #{@instance_id} not in available state, and thus can not be stopped")
59
+ $log.warn("RDS Instance #{@instance_id} state: #{@rds_instance.db_instance_status}")
60
+ return configuration
61
+ end
62
+
63
+ # check if already stopped
64
+ if @rds_instance.db_instance_status == 'stopped'
65
+ $log.info("RDS Instance #{@instance_id} is already stopped")
66
+ return configuration
67
+ end
68
+
69
+ #check if mutli-az RDS. if so, convert to single-az
70
+ if @rds_instance.multi_az
71
+ $log.info("Converting to Non-Multi-AZ instance before stop (instance #{@instance_id}")
72
+ set_rds_instance_multi_az(false)
73
+ end
74
+
75
+ # stop rds instance and wait for it to be fully stopped
76
+ $log.info("Stopping instance #{@instance_id}")
77
+ @rds_client.stop_db_instance({ db_instance_identifier: @instance_id })
78
+ $log.info("Waiting db instance to be stopped #{@instance_id}")
79
+ wait_rds_instance_states(%w(stopping stopped))
80
+
81
+ return configuration
82
+ end
83
+
84
+ def set_rds_instance_multi_az(multi_az)
85
+ if @rds_instance.multi_az == multi_az
86
+ $log.info("Rds instance #{@rds_instance.db_instance_identifier} already multi-az=#{multi_az}")
87
+ return
88
+ end
89
+ @rds_instance.modify({ multi_az: multi_az, apply_immediately: true })
90
+ # allow half an hour for instance to be converted
91
+ wait_states = %w(modifying available)
92
+ self.wait_rds_instance_states( wait_states)
93
+ end
94
+
95
+ def wait_rds_instance_states(wait_states)
96
+ wait_states.each do |state|
97
+ # reached state must be steady, at least a minute. Modifying an instance to/from MultiAZ can't be shorter
98
+ # than 40 seconds, hence steady count is 4
99
+ state_count = 0
100
+ steady_count = 4
101
+ attempts = 0
102
+ rds = Aws::RDS::Resource.new(client: @rds_client)
103
+ until attempts == (max_attempts = 60*6) do
104
+ instance = rds.db_instance(@instance_id)
105
+ $log.info("Instance #{instance.db_instance_identifier} state: #{instance.db_instance_status}, waiting for #{state}")
106
+
107
+ if instance.db_instance_status == "#{state}"
108
+ state_count = state_count + 1
109
+ $log.info("#{state_count}/#{steady_count}")
110
+ else
111
+ state_count = 0
112
+ end
113
+ break if state_count == steady_count
114
+ attempts = attempts + 1
115
+ sleep(15)
116
+ end
117
+
118
+ if attempts == max_attempts
119
+ $log.error("RDS Database Instance #{@instance_id} did not enter #{state} state, however continuing operations...")
120
+ end
121
+ end
122
+ end
123
+
124
+ private :set_rds_instance_multi_az, :wait_rds_instance_states
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../lib/asg_start_stop_handler'
2
+ require_relative '../lib/ec2_start_stop_handler'
3
+ require_relative '../lib/rds_start_stop_handler'
4
+ require_relative '../lib/alarm_start_stop_handler'
5
+
6
+ module Base2
7
+
8
+ class StartStopHandlerFactory
9
+
10
+ # Factory method to get start/stop handler based on CloudFormation
11
+ # resource type. If resource_id passed in does not exist, it is
12
+ # very likely that exception will be raised
13
+ def self.get_start_stop_handler(resource_type, resource_id)
14
+ case resource_type
15
+ when 'AWS::AutoScaling::AutoScalingGroup'
16
+ return Base2::AsgStartStopHandler.new(resource_id)
17
+
18
+ when 'AWS::EC2::Instance'
19
+ return Base2::Ec2StartStopHandler.new(resource_id)
20
+
21
+ when 'AWS::RDS::DBInstance'
22
+ return Base2::RdsStartStopHandler.new(resource_id)
23
+
24
+ when 'AWS::CloudWatch::Alarm'
25
+ return Base2::AlarmStartStopHandler.new(resource_id)
26
+
27
+ else
28
+ return nil
29
+ end
30
+ end
31
+ end
32
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn_manage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Base2Services
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-09-26 00:00:00.000000000 Z
12
+ date: 2017-10-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk
@@ -41,10 +41,15 @@ files:
41
41
  - bin/cfn_manage
42
42
  - bin/cfn_manage.rb
43
43
  - bin/usage.txt
44
+ - lib/alarm_start_stop_handler.rb
45
+ - lib/asg_start_stop_handler.rb
44
46
  - lib/aws_credentials.rb
45
47
  - lib/cf_common.rb
46
48
  - lib/cf_progress_tracker.rb
47
49
  - lib/cf_start_stop_environment.rb
50
+ - lib/ec2_start_stop_handler.rb
51
+ - lib/rds_start_stop_handler.rb
52
+ - lib/start_stop_handler_factory.rb
48
53
  homepage: https://github.com/base2Services/cfn-library/blob/master/README.md
49
54
  licenses:
50
55
  - MIT