cfn_manage 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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