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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7428980b03e64834946d1af37c27d1a3f481d06e8a12a54037265d17938e93ef
4
- data.tar.gz: 046e1384dc663242395149f15577e6540f875c9b7834498f70b4b35fd5df2cbc
3
+ metadata.gz: 343401ecc1402d26222f76e4bcff786ee798fcede9d1b67f6e37dc4a99527886
4
+ data.tar.gz: 95dfb13ac573a995ad875f341043b451d428b568f78f50496c95044cd2ccf1f4
5
5
  SHA512:
6
- metadata.gz: 230c5b07ffa305d5473d69069d154344f43ca340a3cda4b70e3c85dd5132762e8e918be054b08379c0411ef16873aa6ca6f3f9e96d5d206babcd6cf704ef8b15
7
- data.tar.gz: 1c39137b703a1d649cc02c09c9bc5b8ccf15ae5b8535bf1672f4e6d0f006be318b7098c96f106adfea64ed4ecc9200405efee1c1b751669d77775ead54e35f96
6
+ metadata.gz: f52ec460cd5f1ded3b1fb7080b82f309d508d25fac2e5e6cc05f6f4c0334f1858f72dd694a2f5f1529a9088f61cfc74c3d3f874b1fe07df9a011d800dd6ca2e5
7
+ data.tar.gz: 4d73d61e515e309ea5ee40b22728ce539b466319b10dcceef7a4106a1bf24cf06b2edfc43141fda9fee8656bfc00e5a7cdb3147bdac6e9145d7545836015b640
@@ -2,6 +2,7 @@
2
2
  require 'optparse'
3
3
  require 'cfn_manage/version'
4
4
  require 'cfn_manage/cf_common'
5
+ require 'cfn_manage/globals'
5
6
  require 'cfn_manage/cf_start_stop_environment'
6
7
  require 'logger'
7
8
 
@@ -18,6 +19,7 @@ $options['AWS_ASSUME_ROLE'] = ENV['AWS_ASSUME_ROLE']
18
19
 
19
20
  # global logger
20
21
  $log = Logger.new(STDOUT)
22
+ $log.level = Logger::INFO
21
23
 
22
24
  # always flush output
23
25
  STDOUT.sync = true
@@ -77,6 +79,24 @@ OptionParser.new do |opts|
77
79
  opts.on('--alarm [ALARM]') do |alarm|
78
80
  $options['ALARM'] = alarm
79
81
  end
82
+
83
+ opts.on('--asg-wait-state [WAIT_STATE]') do |state|
84
+ allows_values = ['HealthyInASG','Running','HealthyInTargetGroup']
85
+ if !allows_values.include? state
86
+ STDERR.puts("#{type} is not a valid value for `--asg-wait-state`. Use one of #{allows_values.join(',')}")
87
+ exit 1
88
+ end
89
+ CfnManage.asg_wait_state = state
90
+ end
91
+
92
+ opts.on('--ecs-wait-state [WAIT_STATE]') do |state|
93
+ allows_values = ['Running','HealthyInTargetGroup']
94
+ if !allows_values.include? state
95
+ STDERR.puts("#{type} is not a valid value for `--ecs-wait-state`. Use one of #{allows_values.join(',')}")
96
+ exit 1
97
+ end
98
+ CfnManage.ecs_wait_state = state
99
+ end
80
100
 
81
101
  opts.on('-r [AWS_REGION]', '--region [AWS_REGION]') do |region|
82
102
  ENV['AWS_REGION'] = region
@@ -86,29 +106,80 @@ OptionParser.new do |opts|
86
106
  ENV['CFN_AWS_PROFILE'] = profile
87
107
  end
88
108
 
109
+ # Boolean options with support for command line and environment variables
110
+
89
111
  opts.on('--dry-run') do
90
- ENV['DRY_RUN'] = '1'
112
+ CfnManage.dry_run
113
+ end
114
+
115
+ if ENV['DRY_RUN'] == '1'
116
+ CfnManage.dry_run
117
+ end
118
+
119
+ opts.on('--debug') do
120
+ $log.level = Logger::DEBUG
121
+ end
122
+
123
+ if ENV['CFN_DEBUG'] == '1'
124
+ $log.level = Logger::DEBUGß
91
125
  end
92
126
 
93
127
  opts.on('--continue-on-error') do
94
- ENV['CFN_CONTINUE_ON_ERROR'] = '1'
128
+ CfnManage.continue_on_error
129
+ end
130
+
131
+ if ENV['CFN_CONTINUE_ON_ERROR'] == '1'
132
+ CfnManage.continue_on_error
95
133
  end
96
134
 
97
135
  opts.on('--wait-async') do
98
- ENV['WAIT_ASYNC'] = '1'
99
- ENV['SKIP_WAIT'] = '1'
136
+ CfnManage.skip_wait
137
+ CfnManage.wait_async
138
+ end
139
+
140
+ if ENV['WAIT_ASYNC'] == '1'
141
+ CfnManage.skip_wait
142
+ CfnManage.wait_async
100
143
  end
101
144
 
102
145
  opts.on('--skip-wait') do
103
- ENV['SKIP_WAIT'] = '1'
146
+ CfnManage.skip_wait
147
+ end
148
+
149
+ if ENV['SKIP_WAIT'] == '1'
150
+ CfnManage.skip_wait
104
151
  end
105
152
 
106
153
  opts.on('--ignore-missing-ecs-config') do
107
- ENV['IGNORE_MISSING_ECS_CONFIG'] = '1'
154
+ CfnManage.ignore_missing_ecs_config
155
+ end
156
+
157
+ if ENV['IGNORE_MISSING_ECS_CONFIG'] == '1'
158
+ CfnManage.ignore_missing_ecs_config
108
159
  end
109
160
 
110
161
  opts.on('--asg-suspend-termination') do
111
- ENV['ASG_SUSPEND_TERMINATION'] = '1'
162
+ CfnManage.asg_suspend_termination
163
+ end
164
+
165
+ if ENV['ASG_SUSPEND_TERMINATION'] == '1'
166
+ CfnManage.asg_suspend_termination
167
+ end
168
+
169
+ opts.on('--tags') do
170
+ CfnManage.find_tags
171
+ end
172
+
173
+ if ENV['CFN_TAGS'] == '1'
174
+ CfnManage.find_tags
175
+ end
176
+
177
+ opts.on('--ecs-wait-container-instances') do
178
+ CfnManage.ecs_wait_container_instances
179
+ end
180
+
181
+ if ENV['ECS_WAIT_CONTAINER_INSTANCES'] == '1'
182
+ CfnManage.ecs_wait_container_instances
112
183
  end
113
184
 
114
185
  end.parse!
@@ -71,6 +71,10 @@ General options:
71
71
  Applicable only to [start|stop-environment] commands. If dry run is enabled
72
72
  info about assets being started / stopped will ne only printed to standard output,
73
73
  without any action taken.
74
+
75
+ --debug
76
+
77
+ Displays debug logs
74
78
 
75
79
  --continue-on-error
76
80
 
@@ -96,3 +100,30 @@ General options:
96
100
  --asg-suspend-termination
97
101
 
98
102
  Will stop instances in the autoscaling group(s) instead of the default behaviour of termination.
103
+
104
+ --asg-wait-state
105
+
106
+ Allowed values ['HealthyInASG','Running','HealthyInTargetGroup']
107
+ Default: 'HealthyInASG'
108
+
109
+ 'HealthyInASG' - waits for all instances to reach a healthy state in the asg
110
+ 'Running' - waits for all instances to reach the EC2 running state
111
+ 'HealthyInTargetGroup' - waits for all instances to reach a healthy state in all asg assocated target groups
112
+
113
+ --ecs-wait-state
114
+
115
+ Allowed values ['Running','HealthyInTargetGroup']
116
+ Default: 'Skip'
117
+
118
+ 'Running' - waits for all ecs services in cluster to reach the running state
119
+ 'HealthyInTargetGroup' - waits for all ecs services in cluster to reach a healthy state in all assocated target groups
120
+
121
+ --tags
122
+
123
+ will query resource tags for individual resource settings.
124
+ `cfn_manage:priority` for prefered starting order
125
+ will default to defined resource order if no tag is found or resource doesn't support tags
126
+
127
+ --ecs-wait-container-instances
128
+
129
+ waits for a container instance to be active in the ecs cluster before starting services
@@ -1,41 +1,35 @@
1
- require 'aws-sdk-ec2'
1
+ require 'json'
2
+ require 'yaml'
3
+
2
4
  require 'aws-sdk-s3'
3
- require 'aws-sdk-ec2'
4
5
  require 'aws-sdk-cloudformation'
5
- require 'aws-sdk-rds'
6
- require 'aws-sdk-cloudwatch'
7
- require 'aws-sdk-autoscaling'
8
- require 'aws-sdk-ecs'
9
- require 'aws-sdk-docdb'
10
6
 
11
7
  require 'cfn_manage/cf_common'
12
8
  require 'cfn_manage/aws_credentials'
13
- require 'json'
14
- require 'yaml'
9
+ require 'cfn_manage/tag_finder'
15
10
  require 'cfn_manage/start_stop_handler_factory'
16
11
 
17
12
  module CfnManage
18
13
  module CloudFormation
19
14
  class EnvironmentRunStop
20
15
 
21
- @cf_client = nil
22
- @stack_name = nil
23
- @s3_client = nil
24
- @s3_bucket = nil
25
- @credentials = nil
26
- @dry_run = false
27
-
28
- @@resource_start_priorities = {
29
- 'AWS::RDS::DBInstance' => '100',
30
- 'AWS::RDS::DBCluster' => '100',
31
- 'AWS::DocDB::DBCluster' => '100',
32
- 'AWS::AutoScaling::AutoScalingGroup' => '200',
33
- 'AWS::EC2::Instance' => '200',
34
- 'AWS::EC2::SpotFleet' => '200',
35
- 'AWS::Transfer::Server' => '200',
36
- 'AWS::ECS::Cluster' => '250',
37
- 'AWS::CloudWatch::Alarm' => '300'
16
+ DEFAULT_PRIORITIES = {
17
+ 'AWS::RDS::DBInstance' => '100',
18
+ 'AWS::RDS::DBCluster' => '100',
19
+ 'AWS::DocDB::DBCluster' => '100',
20
+ 'AWS::AutoScaling::AutoScalingGroup' => '200',
21
+ 'AWS::EC2::Instance' => '200',
22
+ 'AWS::EC2::SpotFleet' => '200',
23
+ 'AWS::Transfer::Server' => '200',
24
+ 'AWS::ECS::Cluster' => '250',
25
+ 'AWS::CloudWatch::Alarm' => '300'
38
26
  }
27
+
28
+ TAGGED_RESOURCES = %w(
29
+ AWS::AutoScaling::AutoScalingGroup
30
+ AWS::EC2::Instance
31
+ AWS::ECS::Cluster
32
+ )
39
33
 
40
34
  def initialize()
41
35
  @environment_resources = []
@@ -46,10 +40,6 @@ module CfnManage
46
40
  if not @credentials.nil?
47
41
  @cf_client = Aws::CloudFormation::Client.new(credentials: @credentials, retry_limit: 20)
48
42
  end
49
- @dry_run = (ENV.key?('DRY_RUN') and ENV['DRY_RUN'] == '1')
50
- @skip_wait = (ENV.key?('SKIP_WAIT') and ENV['SKIP_WAIT'] == '1')
51
- @wait_async = (ENV.key?('WAIT_ASYNC') and ENV['WAIT_ASYNC'] == '1')
52
- @continue_on_error = (ENV.key? 'CFN_CONTINUE_ON_ERROR' and ENV['CFN_CONTINUE_ON_ERROR'] == '1')
53
43
  rescue NoMethodError => e
54
44
  puts "Got No Method Error on CloudFormation::initialize, this often means that you're missing a AWS_DEFAULT_REGION"
55
45
  rescue Aws::Sigv4::Errors::MissingCredentialsError => e
@@ -62,7 +52,7 @@ module CfnManage
62
52
  Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
63
53
  do_start_assets
64
54
  configuration = { stack_running: true }
65
- save_item_configuration("environment_data/stack-#{stack_name}", configuration) unless @dry_run
55
+ save_item_configuration("environment_data/stack-#{stack_name}", configuration) unless CfnManage.dry_run?
66
56
  $log.info("Environment #{stack_name} started")
67
57
  end
68
58
 
@@ -72,19 +62,31 @@ module CfnManage
72
62
  Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
73
63
  do_stop_assets
74
64
  configuration = { stack_running: false }
75
- save_item_configuration("environment_data/stack-#{stack_name}", configuration) unless @dry_run
65
+ save_item_configuration("environment_data/stack-#{stack_name}", configuration) unless CfnManage.dry_run?
76
66
  $log.info("Environment #{stack_name} stopped")
77
67
  end
78
68
 
79
69
  def start_resource(resource_id,resource_type)
70
+ priority = DEFAULT_PRIORITIES[resource_type]
71
+ options = {}
72
+
73
+ if CfnManage.find_tags?
74
+ tags = CfnManage::TagFiner.new(resource_id)
75
+ tags.get_tags(resource_type)
76
+ priority = !tags.priority.nil? ? tags.priority : priority
77
+ options = tags.options
78
+ $log.debug("setting options #{options} for #{resource_id}")
79
+ end
80
+
80
81
  start_stop_handler = CfnManage::StartStopHandlerFactory.get_start_stop_handler(
81
82
  resource_type,
82
83
  resource_id,
83
- @skip_wait
84
+ options
84
85
  )
86
+
85
87
  @environment_resources << {
86
88
  id: resource_id,
87
- priority: @@resource_start_priorities[resource_type],
89
+ priority: priority,
88
90
  handler: start_stop_handler,
89
91
  type: resource_type
90
92
  }
@@ -92,14 +94,25 @@ module CfnManage
92
94
  end
93
95
 
94
96
  def stop_resource(resource_id,resource_type)
97
+ priority = DEFAULT_PRIORITIES[resource_type]
98
+ options = {}
99
+
100
+ if CfnManage.find_tags?
101
+ tags = CfnManage::TagFiner.new(resource_id)
102
+ tags.get_tags(resource_type)
103
+ priority = !tags.priority.nil? ? tags.priority : priority
104
+ options = tags.options
105
+ end
106
+
95
107
  start_stop_handler = CfnManage::StartStopHandlerFactory.get_start_stop_handler(
96
108
  resource_type,
97
109
  resource_id,
98
- @skip_wait
110
+ options
99
111
  )
112
+
100
113
  @environment_resources << {
101
114
  id: resource_id,
102
- priority: @@resource_start_priorities[resource_type],
115
+ priority: priority,
103
116
  handler: start_stop_handler,
104
117
  type: resource_type
105
118
  }
@@ -116,7 +129,7 @@ module CfnManage
116
129
  begin
117
130
  $log.info("Stopping resource #{resource[:id]}")
118
131
  # just print out information if running a dry run, otherwise start assets
119
- if not @dry_run
132
+ if !CfnManage.dry_run?
120
133
  configuration = resource[:handler].stop()
121
134
  if configuration.class == Hash
122
135
  s3_prefix = "environment_data/resource/#{resource[:id]}"
@@ -130,13 +143,13 @@ module CfnManage
130
143
  $log.error("An exception occurred during stop operation against resource #{resource[:id]}")
131
144
  $log.error("#{e.to_s}")
132
145
  $log.error(e.backtrace.join("\n\t"))
133
- if not @continue_on_error
146
+ if not CfnManage.continue_on_error?
134
147
  raise e
135
148
  end
136
149
  end
137
150
  end
138
151
 
139
- if not @dry_run and @wait_async
152
+ if not CfnManage.dry_run? and CfnManage.wait_async?
140
153
  priority.each do |resource|
141
154
  begin
142
155
  resource[:handler].wait('stopped')
@@ -144,7 +157,7 @@ module CfnManage
144
157
  $log.error("An exception occurred during wait operation against resource #{resource[:id]}")
145
158
  $log.error("#{e.to_s}")
146
159
  $log.error(e.backtrace.join("\n\t"))
147
- if not @continue_on_error
160
+ if not CfnManage.continue_on_error?
148
161
  raise e
149
162
  end
150
163
  end
@@ -164,11 +177,11 @@ module CfnManage
164
177
  begin
165
178
  $log.info("Starting resource #{resource[:id]}")
166
179
  # just print out information if running a dry run, otherwise start assets
167
- if not @dry_run
180
+ if !CfnManage.dry_run?
168
181
  # read configuration
169
182
  s3_prefix = "environment_data/resource/#{resource[:id]}"
170
183
  configuration = get_object_configuration(s3_prefix)
171
-
184
+
172
185
  # start
173
186
  resource[:handler].start(configuration)
174
187
  else
@@ -179,13 +192,13 @@ module CfnManage
179
192
  $log.error("An exception occurred during start operation against resource #{resource[:id]}")
180
193
  $log.error("#{e.to_s}")
181
194
  $log.error(e.backtrace.join("\n\t"))
182
- if not @continue_on_error
195
+ if not CfnManage.continue_on_error?
183
196
  raise e
184
197
  end
185
198
  end
186
199
  end
187
200
 
188
- if not @dry_run and @wait_async
201
+ if not CfnManage.dry_run? and CfnManage.wait_async?
189
202
  priority.each do |resource|
190
203
  begin
191
204
  resource[:handler].wait('available')
@@ -193,7 +206,7 @@ module CfnManage
193
206
  $log.error("An exception occurred during wait operation against resource #{resource[:id]}")
194
207
  $log.error("#{e.to_s}")
195
208
  $log.error(e.backtrace.join("\n\t"))
196
- if not @continue_on_error
209
+ if not CfnManage.continue_on_error?
197
210
  raise e
198
211
  end
199
212
  end
@@ -208,30 +221,45 @@ module CfnManage
208
221
  resrouces = @cf_client.describe_stack_resources(stack_name: stack_name)
209
222
  resrouces['stack_resources'].each do |resource|
210
223
  start_stop_handler = nil
211
- begin
224
+
225
+ resource_id = resource['physical_resource_id']
226
+ resource_type = resource['resource_type']
227
+ priority = DEFAULT_PRIORITIES[resource_type]
228
+ options = {}
229
+
230
+ if CfnManage.find_tags? && TAGGED_RESOURCES.include?(resource_type)
231
+ tags = CfnManage::TagFinder.new(resource_id)
232
+ tags.get_tags(resource_type)
233
+ options = tags.options
234
+ priority = options[:priority] if options.has_key?(:priority)
235
+ $log.debug("setting options #{options} for #{resource_id}")
236
+ end
237
+
238
+ begin
212
239
  start_stop_handler = CfnManage::StartStopHandlerFactory.get_start_stop_handler(
213
- resource['resource_type'],
214
- resource['physical_resource_id'],
215
- @skip_wait
240
+ resource_type,
241
+ resource_id,
242
+ options
216
243
  )
217
244
  rescue Exception => e
218
- $log.error("Error creating start-stop handler for resource of type #{resource['resource_type']}" +
245
+ $log.error("Error creating start-stop handler for resource of type #{resource['resource_type']} " +
219
246
  "and with id #{resource['physical_resource_id']}:#{e}")
220
247
  end
221
- if not start_stop_handler.nil?
222
- resource_id = resource['physical_resource_id']
248
+
249
+ if !start_stop_handler.nil?
250
+ $log.debug("priority set to #{priority} for resource id: #{resource_id}, type: #{resource_type}")
223
251
  @environment_resources << {
224
252
  id: resource_id,
225
- priority: @@resource_start_priorities[resource['resource_type']],
253
+ priority: priority,
226
254
  handler: start_stop_handler,
227
- type: resource['resource_type']
255
+ type: resource_type
228
256
  }
229
257
  end
230
258
  end
231
259
  end
232
260
 
233
261
  def get_object_configuration(s3_prefix)
234
- configuration = nil
262
+ configuration = {}
235
263
  begin
236
264
  key = "#{s3_prefix}/latest/config.json"
237
265
  $log.info("Reading object configuration from s3://#{@s3_bucket}/#{key}")
@@ -267,4 +295,4 @@ module CfnManage
267
295
 
268
296
  end
269
297
  end
270
- end
298
+ end