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.
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