cfn_manage 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ require 'cfn_manage/aws_credentials'
2
+
3
+ module CfnManage
4
+ module StartStopHandler
5
+ class SpotFleet
6
+
7
+ def initialize(fleet_id, options = {})
8
+ @fleet_id = fleet_id
9
+ credentials = CfnManage::AWSCredentials.get_session_credentials("startstopfleet_#{fleet_id}")
10
+ @ec2_client = Aws::EC2::Client.new(retry_limit: 20)
11
+ if credentials != nil
12
+ @ec2_client = Aws::EC2::Client.new(credentials: credentials, retry_limit: 20)
13
+ end
14
+
15
+ @fleet = @ec2_client.describe_spot_fleet_requests({spot_fleet_request_ids:[fleet_id]})
16
+ @fleet = @fleet.spot_fleet_request_configs[0].spot_fleet_request_config
17
+ end
18
+
19
+ def start(configuration)
20
+
21
+ $log.info("Setting fleet #{@fleet_id} capacity to #{configuration['target_capacity']}")
22
+ @ec2_client.modify_spot_fleet_request({
23
+ spot_fleet_request_id: @fleet_id,
24
+ target_capacity: configuration['target_capacity'],
25
+ })
26
+
27
+ return configuration
28
+ end
29
+
30
+ def stop
31
+
32
+ if @fleet.target_capacity == 0
33
+ $log.info("Spot fleet #{@fleet_id} already stopped")
34
+ return nil
35
+ end
36
+
37
+ configuration = {
38
+ target_capacity: @fleet.target_capacity
39
+ }
40
+
41
+ $log.info("Setting fleet #{@fleet_id} capacity to 0")
42
+ @ec2_client.modify_spot_fleet_request({
43
+ spot_fleet_request_id: @fleet_id,
44
+ target_capacity: 0,
45
+ })
46
+
47
+ return configuration
48
+ end
49
+
50
+ def wait(wait_states=[])
51
+ $log.debug("Not waiting for spot fleet #{@fleet_id}")
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,96 @@
1
+ require 'cfn_manage/aws_credentials'
2
+ require 'aws-sdk-transfer'
3
+
4
+ module CfnManage
5
+ module StartStopHandler
6
+ class Transfer
7
+
8
+ def initialize(server_id, options = {})
9
+ sftpId = server_id.split("/")
10
+ @server_id = sftpId.last
11
+ credentials = CfnManage::AWSCredentials.get_session_credentials("startstoptransfer_#{@server_id}")
12
+ @client = Aws::Transfer::Client.new(retry_limit: 20)
13
+ if credentials != nil
14
+ @client = Aws::Transfer::Client.new(credentials: credentials, retry_limit: 20)
15
+ end
16
+ end
17
+
18
+ def start(configuration)
19
+
20
+ state = get_state()
21
+
22
+ if state != "OFFLINE"
23
+ $log.warn("SFTP Server #{@server_id} is in a state of #{state} and can not be started.")
24
+ return
25
+ end
26
+
27
+ $log.info("Starting SFTP Server #{@server_id}")
28
+ @client.start_server({
29
+ server_id: @server_id,
30
+ })
31
+ unless CfnManage.skip_wait?
32
+ $log.info("Waiting for SFTP to start #{@cluster_id}")
33
+ wait('ONLINE')
34
+ end
35
+
36
+ return configuration
37
+ end
38
+
39
+ def stop()
40
+
41
+ state = get_state()
42
+
43
+ if state != "ONLINE"
44
+ $log.warn("SFTP Server #{@server_id} is in a state of #{state} and can not be stopped.")
45
+ return {}
46
+ end
47
+
48
+ @client.stop_server({
49
+ server_id: @server_id,
50
+ })
51
+ unless CfnManage.skip_wait?
52
+ $log.info("Waiting for SFTP to stop #{@cluster_id}")
53
+ wait('OFFLINE')
54
+ end
55
+ return {}
56
+ end
57
+
58
+ def get_state()
59
+ resp = @client.describe_server({
60
+ server_id: @server_id,
61
+ })
62
+ return resp.server.state
63
+ end
64
+
65
+ def wait(completed_state)
66
+
67
+ state_count = 0
68
+ steady_count = 2
69
+ attempts = 0
70
+ until attempts == (max_attempts = 60*6) do
71
+ state = get_state()
72
+ $log.info("SFTP Server #{@server_id} state: #{state}, waiting for #{completed_state}")
73
+
74
+ if state == "#{completed_state}"
75
+ state_count = state_count + 1
76
+ $log.info("#{state_count}/#{steady_count}")
77
+ elsif ["START_FAILED", "STOP_FAILED"].include?(state)
78
+ $log.error("SFTP Server #{@server_id} failed to reach state #{completed_state} with current state #{state}!")
79
+ break
80
+ else
81
+ state_count = 0
82
+ end
83
+ break if state_count == steady_count
84
+ attempts = attempts + 1
85
+ sleep(15)
86
+ end
87
+
88
+ if attempts == max_attempts
89
+ $log.error("SFTP Server #{@server_id} did not enter #{completed_state} state, however continuing operations...")
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -1,12 +1,12 @@
1
- require 'cfn_manage/asg_start_stop_handler'
2
- require 'cfn_manage/ec2_start_stop_handler'
3
- require 'cfn_manage/rds_start_stop_handler'
4
- require 'cfn_manage/aurora_cluster_start_stop_handler'
5
- require 'cfn_manage/alarm_start_stop_handler'
6
- require 'cfn_manage/spot_fleet_start_stop_handler'
7
- require 'cfn_manage/ecs_cluster_start_stop_handler'
8
- require 'cfn_manage/documentdb_cluster_start_stop_handler'
9
- require 'cfn_manage/transfer_start_stop_handler'
1
+ require 'cfn_manage/handlers/asg'
2
+ require 'cfn_manage/handlers/ec2'
3
+ require 'cfn_manage/handlers/rds'
4
+ require 'cfn_manage/handlers/aurora_cluster'
5
+ require 'cfn_manage/handlers/alarm'
6
+ require 'cfn_manage/handlers/spot_fleet'
7
+ require 'cfn_manage/handlers/ecs_cluster'
8
+ require 'cfn_manage/handlers/documentdb'
9
+ require 'cfn_manage/handlers/transfer'
10
10
 
11
11
  module CfnManage
12
12
 
@@ -15,34 +15,34 @@ module CfnManage
15
15
  # Factory method to get start/stop handler based on CloudFormation
16
16
  # resource type. If resource_id passed in does not exist, it is
17
17
  # very likely that exception will be raised
18
- def self.get_start_stop_handler(resource_type, resource_id, skip_wait)
18
+ def self.get_start_stop_handler(resource_type, resource_id, options)
19
19
  case resource_type
20
20
  when 'AWS::AutoScaling::AutoScalingGroup'
21
- return CfnManage::AsgStartStopHandler.new(resource_id, skip_wait)
21
+ return CfnManage::StartStopHandler::Asg.new(resource_id,options)
22
22
 
23
23
  when 'AWS::EC2::Instance'
24
- return CfnManage::Ec2StartStopHandler.new(resource_id, skip_wait)
24
+ return CfnManage::StartStopHandler::Ec2.new(resource_id,options)
25
25
 
26
26
  when 'AWS::RDS::DBInstance'
27
- return CfnManage::RdsStartStopHandler.new(resource_id, skip_wait)
27
+ return CfnManage::StartStopHandler::Rds.new(resource_id,options)
28
28
 
29
29
  when 'AWS::RDS::DBCluster'
30
- return CfnManage::AuroraClusterStartStopHandler.new(resource_id, skip_wait)
30
+ return CfnManage::StartStopHandler::AuroraCluster.new(resource_id,options)
31
31
 
32
32
  when 'AWS::DocDB::DBCluster'
33
- return CfnManage::DocumentDbClusterStartStopHandler.new(resource_id, skip_wait)
33
+ return CfnManage::StartStopHandler::DocumentDb.new(resource_id,options)
34
34
 
35
35
  when 'AWS::CloudWatch::Alarm'
36
- return CfnManage::AlarmStartStopHandler.new(resource_id)
36
+ return CfnManage::StartStopHandler::Alarm.new(resource_id,options)
37
37
 
38
38
  when 'AWS::EC2::SpotFleet'
39
- return CfnManage::SpotFleetStartStopHandler.new(resource_id, skip_wait)
39
+ return CfnManage::StartStopHandler::SpotFleet.new(resource_id,options)
40
40
 
41
41
  when 'AWS::ECS::Cluster'
42
- return CfnManage::EcsClusterStartStopHandler.new(resource_id, skip_wait)
42
+ return CfnManage::StartStopHandler::EcsCluster.new(resource_id,options)
43
43
 
44
44
  when 'AWS::Transfer::Server'
45
- return CfnManage::TransferStartStopHandler.new(resource_id, skip_wait)
45
+ return CfnManage::StartStopHandler::Transfer.new(resource_id,options)
46
46
 
47
47
  else
48
48
  return nil
@@ -0,0 +1,77 @@
1
+ require 'cfn_manage/aws_credentials'
2
+
3
+ require 'aws-sdk-autoscaling'
4
+
5
+ module CfnManage
6
+ class TagFinder
7
+
8
+ attr_reader :priority, :opts
9
+
10
+ def initialize(resource_id)
11
+ @resource_id = resource_id
12
+ @tags = []
13
+ end
14
+
15
+ def get_tags(resource_type)
16
+ case resource_type
17
+ when 'AWS::AutoScaling::AutoScalingGroup'
18
+ asg()
19
+ when 'AWS::EC2::Instance'
20
+ ec2()
21
+ when 'AWS::ECS::Cluster'
22
+ ecs_cluster()
23
+ end
24
+ end
25
+
26
+ def priority()
27
+ @tags.select {|tag| tag.key == 'cfn_manage:prority'}.collect {|tag| tag.value}.first
28
+ end
29
+
30
+ def options()
31
+ # collect all the cfn_manage tags and pass the back as a hash
32
+ # so they can be passed into the resource handers
33
+ options = @tags.select {|tag| tag.key.start_with?('cfn_manage:') }
34
+ options.collect { |tag| { tag.key.split(':').last.to_sym => tag.value } }.reduce(Hash.new,:merge)
35
+ end
36
+
37
+ def asg()
38
+ credentials = CfnManage::AWSCredentials.get_session_credentials("cfn_manage_get_tags")
39
+ client = Aws::AutoScaling::Client.new(credentials: credentials, retry_limit: 20)
40
+ resp = client.describe_tags({
41
+ filters: [
42
+ {
43
+ name: "auto-scaling-group",
44
+ values: [@resource_id]
45
+ }
46
+ ]
47
+ })
48
+ @tags = resp.tags
49
+ end
50
+
51
+ def ec2()
52
+ credentials = CfnManage::AWSCredentials.get_session_credentials("cfn_manage_get_tags")
53
+ client = Aws::EC2::Client.new(credentials: credentials, retry_limit: 20)
54
+ resp = client.describe_tags({
55
+ filters: [
56
+ {
57
+ name: "resource-id",
58
+ values: [@resource_id]
59
+ }
60
+ ]
61
+ })
62
+ @tags = resp.tags
63
+ end
64
+
65
+ def ecs_cluster()
66
+ credentials = CfnManage::AWSCredentials.get_session_credentials("cfn_manage_get_tags")
67
+ client = Aws::ECS::Client.new(credentials: credentials, retry_limit: 20)
68
+ resp = client.describe_clusters({
69
+ clusters: [@resource_id],
70
+ include: ["TAGS"]
71
+ })
72
+ cluster = resp.clusters.first
73
+ @tags = cluster.tags
74
+ end
75
+
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module CfnManage
2
- VERSION="0.7.1".freeze
2
+ VERSION="0.8.0".freeze
3
3
  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.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Base2Services
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-08-15 00:00:00.000000000 Z
13
+ date: 2019-10-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: aws-sdk-core
@@ -232,6 +232,26 @@ dependencies:
232
232
  - - "<"
233
233
  - !ruby/object:Gem::Version
234
234
  version: '2'
235
+ - !ruby/object:Gem::Dependency
236
+ name: aws-sdk-elasticloadbalancingv2
237
+ requirement: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - "~>"
240
+ - !ruby/object:Gem::Version
241
+ version: '1'
242
+ - - "<"
243
+ - !ruby/object:Gem::Version
244
+ version: '2'
245
+ type: :runtime
246
+ prerelease: false
247
+ version_requirements: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - "~>"
250
+ - !ruby/object:Gem::Version
251
+ version: '1'
252
+ - - "<"
253
+ - !ruby/object:Gem::Version
254
+ version: '2'
235
255
  - !ruby/object:Gem::Dependency
236
256
  name: bundler
237
257
  requirement: !ruby/object:Gem::Requirement
@@ -340,20 +360,22 @@ files:
340
360
  - bin/cfn_manage
341
361
  - bin/usage.txt
342
362
  - lib/cfn_manage.rb
343
- - lib/cfn_manage/alarm_start_stop_handler.rb
344
- - lib/cfn_manage/asg_start_stop_handler.rb
345
- - lib/cfn_manage/aurora_cluster_start_stop_handler.rb
346
363
  - lib/cfn_manage/aws_credentials.rb
347
364
  - lib/cfn_manage/cf_common.rb
348
365
  - lib/cfn_manage/cf_progress_tracker.rb
349
366
  - lib/cfn_manage/cf_start_stop_environment.rb
350
- - lib/cfn_manage/documentdb_cluster_start_stop_handler.rb
351
- - lib/cfn_manage/ec2_start_stop_handler.rb
352
- - lib/cfn_manage/ecs_cluster_start_stop_handler.rb
353
- - lib/cfn_manage/rds_start_stop_handler.rb
354
- - lib/cfn_manage/spot_fleet_start_stop_handler.rb
367
+ - lib/cfn_manage/globals.rb
368
+ - lib/cfn_manage/handlers/alarm.rb
369
+ - lib/cfn_manage/handlers/asg.rb
370
+ - lib/cfn_manage/handlers/aurora_cluster.rb
371
+ - lib/cfn_manage/handlers/documentdb.rb
372
+ - lib/cfn_manage/handlers/ec2.rb
373
+ - lib/cfn_manage/handlers/ecs_cluster.rb
374
+ - lib/cfn_manage/handlers/rds.rb
375
+ - lib/cfn_manage/handlers/spot_fleet.rb
376
+ - lib/cfn_manage/handlers/transfer.rb
355
377
  - lib/cfn_manage/start_stop_handler_factory.rb
356
- - lib/cfn_manage/transfer_start_stop_handler.rb
378
+ - lib/cfn_manage/tag_finder.rb
357
379
  - lib/cfn_manage/version.rb
358
380
  homepage: https://github.com/base2Services/cfn-start-stop-stack/blob/master/README.md
359
381
  licenses:
@@ -365,16 +387,16 @@ require_paths:
365
387
  - lib
366
388
  required_ruby_version: !ruby/object:Gem::Requirement
367
389
  requirements:
368
- - - ">="
390
+ - - "~>"
369
391
  - !ruby/object:Gem::Version
370
- version: '0'
392
+ version: '2.5'
371
393
  required_rubygems_version: !ruby/object:Gem::Requirement
372
394
  requirements:
373
395
  - - ">="
374
396
  - !ruby/object:Gem::Version
375
397
  version: '0'
376
398
  requirements: []
377
- rubygems_version: 3.0.4
399
+ rubygems_version: 3.0.6
378
400
  signing_key:
379
401
  specification_version: 4
380
402
  summary: Manage AWS Cloud Formation stacks
@@ -1,44 +0,0 @@
1
- require 'cfn_manage/aws_credentials'
2
-
3
- module CfnManage
4
-
5
- class AlarmStartStopHandler
6
-
7
- def initialize(alarm_name)
8
- @alarm_id = alarm_name
9
- credentials = CfnManage::AWSCredentials.get_session_credentials("startstopalarm_#{@asg_name}")
10
- @cwclient = Aws::CloudWatch::Client.new(retry_limit: 20)
11
- if credentials != nil
12
- @cwclient = Aws::CloudWatch::Client.new(credentials: credentials, retry_limit: 20)
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
-
38
- def wait(wait_states=[])
39
- $log.debug("Not waiting for alarm #{@alarm_id}")
40
- end
41
-
42
- end
43
-
44
- end
@@ -1,181 +0,0 @@
1
- require 'cfn_manage/aws_credentials'
2
-
3
- module CfnManage
4
-
5
- class AsgStartStopHandler
6
-
7
- def initialize(asg_id, skip_wait)
8
- @asg_name = asg_id
9
- @skip_wait = skip_wait
10
- @asg_suspend_termination = (ENV.key?('ASG_SUSPEND_TERMINATION') and ENV['ASG_SUSPEND_TERMINATION'] == '1')
11
- credentials = CfnManage::AWSCredentials.get_session_credentials("stopasg_#{@asg_name}")
12
- @asg_client = Aws::AutoScaling::Client.new(retry_limit: 20)
13
- @ec2_client = Aws::EC2::Client.new(retry_limit: 20)
14
- if credentials != nil
15
- @asg_client = Aws::AutoScaling::Client.new(credentials: credentials, retry_limit: 20)
16
- @ec2_client = Aws::EC2::Client.new(credentials: credentials, retry_limit: 20)
17
- end
18
-
19
- asg_details = @asg_client.describe_auto_scaling_groups(
20
- auto_scaling_group_names: [@asg_name]
21
- )
22
- if asg_details.auto_scaling_groups.size() == 0
23
- raise "Couldn't find ASG #{@asg_name}"
24
- end
25
- @asg = asg_details.auto_scaling_groups[0]
26
- end
27
-
28
- def stop
29
- # check if already stopped
30
- if @asg.min_size == @asg.max_size and @asg.max_size == @asg.desired_capacity and @asg.min_size == 0
31
- $log.info("ASG #{@asg_name} already stopped")
32
- # nil and false configurations are not saved
33
- return nil
34
- else
35
-
36
- puts @asg.auto_scaling_group_name
37
-
38
- unless @asg_suspend_termination
39
- # store asg configuration to S3
40
- configuration = {
41
- desired_capacity: @asg.desired_capacity,
42
- min_size: @asg.min_size,
43
- max_size: @asg.max_size
44
- }
45
-
46
- $log.info("Setting desired capacity to 0/0/0 for ASG #{@asg.auto_scaling_group_name}A")
47
-
48
- puts @asg.auto_scaling_group_name
49
- @asg_client.update_auto_scaling_group({
50
- auto_scaling_group_name: "#{@asg.auto_scaling_group_name}",
51
- min_size: 0,
52
- max_size: 0,
53
- desired_capacity: 0
54
- })
55
- return configuration
56
- else
57
-
58
- configuration = {
59
- desired_capacity: @asg.desired_capacity,
60
- min_size: @asg.min_size,
61
- max_size: @asg.max_size,
62
- suspended_processes: @asg.suspended_processes
63
- }
64
-
65
- $log.info("Suspending processes for ASG #{@asg.auto_scaling_group_name}A")
66
-
67
- @asg_client.suspend_processes({
68
- auto_scaling_group_name: "#{@asg.auto_scaling_group_name}",
69
- })
70
-
71
- $log.info("Stopping all instances in ASG #{@asg.auto_scaling_group_name}A")
72
-
73
- @asg.instances.each do |instance|
74
- @instance_id = instance.instance_id
75
- @instance = Aws::EC2::Resource.new(client: @ec2_client, retry_limit: 20).instance(@instance_id)
76
-
77
- if %w(stopped stopping).include?(@instance.state.name)
78
- $log.info("Instance #{@instance_id} already stopping or stopped")
79
- return
80
- end
81
-
82
- $log.info("Stopping instance #{@instance_id}")
83
- @instance.stop()
84
- end
85
-
86
- return configuration
87
-
88
- end
89
-
90
- end
91
-
92
- end
93
-
94
- def start(configuration)
95
- if configuration.nil?
96
- $log.warn("No configuration found for #{@asg_name}, skipping..")
97
- return
98
- end
99
- $log.info("Starting ASG #{@asg_name} with following configuration\n#{configuration}")
100
-
101
- unless @asg_suspend_termination
102
- # restore asg sizes
103
- @asg_client.update_auto_scaling_group({
104
- auto_scaling_group_name: @asg_name,
105
- min_size: configuration['min_size'],
106
- max_size: configuration['max_size'],
107
- desired_capacity: configuration['desired_capacity']
108
- })
109
- else
110
-
111
- $log.info("Starting instances for ASG #{@asg_name}...")
112
-
113
- @asg.instances.each do |instance|
114
- @instance_id = instance.instance_id
115
- @instance = Aws::EC2::Resource.new(client: @ec2_client, retry_limit: 20).instance(@instance_id)
116
-
117
- if %w(running).include?(@instance.state.name)
118
- $log.info("Instance #{@instance_id} already running")
119
- return
120
- end
121
- $log.info("Starting instance #{@instance_id}")
122
- @instance.start()
123
- end
124
-
125
- unhealthy = true
126
-
127
- $log.info("Checking health status for instances for ASG #{@asg_name}")
128
-
129
- while unhealthy do
130
-
131
- asg_curr_details = @asg_client.describe_auto_scaling_groups(
132
- auto_scaling_group_names: [@asg_name]
133
- )
134
- @asg_status = asg_curr_details.auto_scaling_groups[0]
135
-
136
- allHealthy = 0
137
-
138
- @asg_status.instances.each do |instance|
139
- @instance_health = instance.health_status
140
- if @instance_health == "Healthy"
141
- allHealthy += 1
142
- else
143
- $log.info("Instance #{instance.instance_id} not currently healthy...")
144
- sleep(15)
145
- end
146
- end
147
-
148
- if allHealthy == @asg_status.instances.length
149
- $log.info("All instances healthy in ASG #{@asg_name}")
150
- unhealthy = false
151
- break
152
- end
153
-
154
- end
155
-
156
- $log.info("Resuming all processes for ASG #{@asg_name}")
157
-
158
- @asg_client.resume_processes({
159
- auto_scaling_group_name: "#{@asg.auto_scaling_group_name}",
160
- })
161
-
162
- if configuration.key?(:suspended_processes)
163
-
164
- $log.info("Suspending processes stored in configuration for ASG #{@asg_name}")
165
-
166
- @asg_client.suspend_processes({
167
- auto_scaling_group_name: "#{@asg.auto_scaling_group_name}",
168
- scaling_processes: configuration['suspended_processes'],
169
- })
170
- end
171
-
172
- end
173
-
174
- end
175
-
176
- def wait(wait_states=[])
177
- $log.debug("Not waiting for ASG #{@asg_name}")
178
- end
179
-
180
- end
181
- end