cfn_manage 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6e4f78a5035f0689fbfc63085368bd1614fe61bc
4
+ data.tar.gz: 155ff3f1c89b73db2412761cc95e6924a7c6be53
5
+ SHA512:
6
+ metadata.gz: b64b4a25627848983eea551310e6c7dc5fb6075dc66e3e41731683b78f86bc60909ef15d21662115df876864e63bfa812b57688a734f93ccd7e3e6d42bf052f1
7
+ data.tar.gz: 5e403600572982b4c5d92e48cba19329ce500655727cfe521770cd3a6204e7ce24579cce71d996803a66fb014ca2686e9728d5283e65ff3a888222909ccc34f7
data/bin/cfn_manage ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative('./cfn_manage')
data/bin/cfn_manage.rb ADDED
@@ -0,0 +1,95 @@
1
+ require 'optparse'
2
+ require_relative '../lib/cf_common'
3
+ require_relative '../lib/cf_start_stop_environment'
4
+ require 'logger'
5
+
6
+ # exit with usage information
7
+ def print_usage_exit(code)
8
+ STDERR.puts(File.open("#{File.expand_path(File.dirname(__FILE__))}/usage.txt").read)
9
+ exit code
10
+ end
11
+
12
+ # global options
13
+ $options = {}
14
+ $options['SOURCE_BUCKET'] = ENV['SOURCE_BUCKET']
15
+ $options['AWS_ASSUME_ROLE'] = ENV['AWS_ASSUME_ROLE']
16
+
17
+ # global logger
18
+ $log = Logger.new(STDOUT)
19
+
20
+ # always flush output
21
+ STDOUT.sync = true
22
+
23
+ # parse command line options
24
+ OptionParser.new do |opts|
25
+
26
+ opts.banner = 'Usage: cfn_manage [command] [options]'
27
+
28
+ opts.on('--source-bucket [BUCKET]') do |bucket|
29
+ $options['SOURCE_BUCKET'] = bucket
30
+ ENV['SOURCE_BUCKET'] = bucket
31
+ end
32
+
33
+ opts.on('--aws-role [ROLE]') do |role|
34
+ ENV['AWS_ASSUME_ROLE'] = role
35
+ end
36
+
37
+ opts.on('--stack-name [STACK_NAME]') do |stack|
38
+ $options['STACK'] = stack
39
+ end
40
+
41
+ opts.on('--asg-name [ASG]') do |asg|
42
+ $options['ASG'] = asg
43
+ end
44
+
45
+ opts.on('--rds-instance-id [RDS_INSTANCE_ID]') do |asg|
46
+ $options['RDS_INSTANCE_ID'] = asg
47
+ end
48
+
49
+ opts.on('--stack-name [STACK_NAME]') do |asg|
50
+ $options['STACK_NAME'] = asg
51
+ end
52
+
53
+ opts.on('-r [AWS_REGION]', '--region [AWS_REGION]') do |region|
54
+ ENV['AWS_REGION'] = region
55
+ end
56
+
57
+ opts.on('-p [AWS_PROFILE]', '--profile [AWS_PROFILE]') do |profile|
58
+ ENV['CFN_AWS_PROFILE'] = profile
59
+ end
60
+
61
+ opts.on('--dry-run') do
62
+ ENV['DRY_RUN'] = '1'
63
+ end
64
+
65
+ end.parse!
66
+
67
+ command = ARGV[0]
68
+
69
+ if command.nil?
70
+ print_usage_exit(-1)
71
+ end
72
+
73
+ # execute action based on command
74
+ case command
75
+ when 'help'
76
+ print_usage_exit(0)
77
+ # asg commands
78
+ when 'stop-asg'
79
+ Base2::CloudFormation::EnvironmentRunStop.new().start_stop_asg('stop', $options['ASG'])
80
+ when 'start-asg'
81
+ Base2::CloudFormation::EnvironmentRunStop.new().start_stop_asg('start', $options['ASG'])
82
+
83
+ # rds commands
84
+ when 'stop-rds'
85
+ Base2::CloudFormation::EnvironmentRunStop.new().start_stop_rds('stop', $options['RDS_INSTANCE_ID'])
86
+ when 'start-rds'
87
+ Base2::CloudFormation::EnvironmentRunStop.new().start_stop_rds('start', $options['RDS_INSTANCE_ID'])
88
+
89
+ # stack commands
90
+ # rds commands
91
+ when 'stop-environment'
92
+ Base2::CloudFormation::EnvironmentRunStop.new().stop_environment($options['STACK_NAME'])
93
+ when 'start-environment'
94
+ Base2::CloudFormation::EnvironmentRunStop.new().start_environment($options['STACK_NAME'])
95
+ end
data/bin/usage.txt ADDED
@@ -0,0 +1,42 @@
1
+ Usage: cfn_manage [command] [options]
2
+
3
+ Commands:
4
+
5
+ cfn_manage stop-environment --stack-name [STACK_NAME]
6
+
7
+ cfn_manage start-environment --stack-name [STACK_NAME]
8
+
9
+ cfn_manage stop-asg --asg-name [ASG]
10
+
11
+ cfn_manage start-asg --asg-name [ASG]
12
+
13
+ cfn_manage stop-rds --rds-instance-id [RDS_INSTANCE_ID]
14
+
15
+ cfn_manage start-rds --rds-instance-id [RDS_INSTANCE_ID]
16
+
17
+
18
+ General options
19
+
20
+ --source-bucket [BUCKET]
21
+
22
+ Pucket used to store / pull information from
23
+
24
+ --aws-role [ROLE_ARN]
25
+
26
+ AWS Role to assume when performing operations. Any reads and
27
+ write to source bucket will be performed outside of this role
28
+
29
+
30
+ -r [AWS_REGION], --region [AWS_REGION]
31
+
32
+ AWS Region to use when making API calls
33
+
34
+ -p [AWS_PROFILE], --profile [AWS_PROFILE]
35
+
36
+ AWS Shared profile to use when making API calls
37
+
38
+ --dry-run
39
+
40
+ Applicable only to [start|stop-environment] commands. If dry run is enabled
41
+ info about assets being started / stopped will ne only printed to standard output,
42
+ without any action taken.
@@ -0,0 +1,36 @@
1
+ require 'aws-sdk'
2
+
3
+ module Base2
4
+
5
+ class AWSCredentials
6
+
7
+ def self.get_session_credentials(session_name)
8
+
9
+ #check if AWS_ASSUME_ROLE exists
10
+ session_name = "#{session_name.gsub('_','-')}-#{Time.now.getutc.to_i}"
11
+ if session_name.length > 64
12
+ session_name = session_name[-64..-1]
13
+ end
14
+ assume_role = ENV['AWS_ASSUME_ROLE'] or nil
15
+ if not assume_role.nil?
16
+ return Aws::AssumeRoleCredentials.new(
17
+ role_arn: assume_role,
18
+ role_session_name: session_name
19
+ )
20
+ end
21
+
22
+ # check if explicitly set shared credentials profile
23
+ if ENV.key?('CFN_AWS_PROFILE')
24
+ return Aws::SharedCredentials.new(profile_name: ENV['CFN_AWS_PROFILE'])
25
+ end
26
+
27
+ # check if Instance Profile available
28
+ credentials = Aws::InstanceProfileCredentials.new(retries: 2, http_open_timeout:1)
29
+ return credentials unless credentials.credentials.access_key_id.nil?
30
+
31
+ # use default profile
32
+ return Aws::SharedCredentials.new()
33
+
34
+ end
35
+ end
36
+ end
data/lib/cf_common.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Base2
2
+
3
+ module CloudFormation
4
+
5
+ class Common
6
+
7
+ def self.visit_stack(cf_client, stack_name, handler, visit_substacks)
8
+ stack_resources = cf_client.describe_stack_resources(stack_name: stack_name)
9
+ stack = cf_client.describe_stacks(stack_name: stack_name)
10
+
11
+ # call traverse handler for parent stack
12
+ handler.call(stack['stacks'][0].stack_name)
13
+
14
+ # do not traverse unless instructed
15
+ return unless visit_substacks
16
+
17
+ stack_resources['stack_resources'].each do |resource|
18
+ # test if resource us substack
19
+ unless (resource['physical_resource_id'] =~ /arn:aws:cloudformation:(.*):stack\/(.*)/).nil?
20
+ # call recursively
21
+ self.visit_stack(cf_client, resource['physical_resource_id'], handler, visit_substacks)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ require 'aws-sdk'
2
+ require_relative './cf_common'
3
+
4
+ module Base2
5
+ module CloudFormation
6
+ class ProgressTracker
7
+ @cf_client = nil
8
+ @stack_name = nil
9
+ @last_event_times = {}
10
+ @period_from = nil
11
+
12
+ @@default_ending_states = %w[
13
+ CREATE_COMPLETE
14
+ UPDATE_COMPLETE
15
+ UPDATE_ROLLBACK_COMPLETE
16
+ ROLLBACK_FAILED
17
+ DELETE_FAILED
18
+ ]
19
+
20
+ @@default_display_state = %w[
21
+ CREATE_COMPLETE
22
+ UPDATE_COMPLETE
23
+ ]
24
+
25
+ @ending_states = nil
26
+
27
+ def initialize(stack_name, period_from, creds = nil, region = nil)
28
+ client_params = {}
29
+ client_params['region'] = region unless region.nil?
30
+ client_params['credentials'] = creds unless creds.nil?
31
+ @cf_client = Aws::CloudFormation::Client.new(client_params)
32
+ @stack_name = stack_name
33
+ @ending_statest = @@default_ending_states
34
+ @period_from = period_from
35
+ end
36
+
37
+
38
+ def track_single_stack(stack)
39
+ stack_id = stack['stack_id']
40
+ # Default to period_from if first run, take from last run otherwise
41
+ event_from = last_event_times[stack_id] if @last_event_times.key?(stack_id)
42
+ event_from = @period_from unless @last_event_times.key?(stack_id)
43
+
44
+
45
+ stack_resources = @cf_client.describe_stack_events(stack_name: stack['stack_id'],)
46
+
47
+
48
+ end
49
+
50
+ def track_progress(_show_only_failures = false)
51
+ Common.visit_stack(@cf_client, @stack_name, method(:track_single_stack),true)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,357 @@
1
+ require 'aws-sdk'
2
+ require_relative '../lib/cf_common'
3
+ require_relative '../lib/aws_credentials'
4
+ require 'json'
5
+ require 'yaml'
6
+
7
+ module Base2
8
+ module CloudFormation
9
+ class EnvironmentRunStop
10
+
11
+ @cf_client = nil
12
+ @stack_name = nil
13
+ @s3_client = nil
14
+ @s3_bucket = nil
15
+ @credentials = nil
16
+ @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
+
23
+ @@resource_start_priorities = {
24
+ 'AWS::RDS::DBInstance' => '100',
25
+ 'AWS::AutoScaling::AutoScalingGroup' => '200',
26
+ 'AWS::EC2::Instance' => '200'
27
+ }
28
+
29
+ @environment_resources = nil
30
+
31
+ def initialize()
32
+ @environment_resources = []
33
+ @s3_client = Aws::S3::Client.new()
34
+ @s3_bucket = ENV['SOURCE_BUCKET']
35
+ @cf_client = Aws::CloudFormation::Client.new()
36
+ @credentials = Base2::AWSCredentials.get_session_credentials('start_stop_environment')
37
+ if not @credentials.nil?
38
+ @cf_client = Aws::CloudFormation::Client.new(credentials: @credentials)
39
+ end
40
+ @dry_run = ENV.key?('DRY_RUN') and ENV['DRY_RUN'] == '1'
41
+ end
42
+
43
+
44
+ def start_environment(stack_name)
45
+ $log.info("Starting environment #{stack_name}")
46
+ Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
47
+ do_start_assets
48
+ configuration = {stack_running: true}
49
+ save_item_configuration("environment-data/stack-data/#{stack_name}", configuration) unless @dry_run
50
+ $log.info("Environment #{stack_name} started")
51
+ end
52
+
53
+
54
+ def stop_environment(stack_name)
55
+ $log.info("Stopping environment #{stack_name}")
56
+ Common.visit_stack(@cf_client, stack_name, method(:collect_resources), true)
57
+ do_stop_assets
58
+ configuration = {stack_running: false}
59
+ save_item_configuration("environment-data/stack-data/#{stack_name}", configuration) unless @dry_run
60
+ $log.info("Environment #{stack_name} stopped")
61
+ end
62
+
63
+
64
+ def do_stop_assets
65
+ # sort start resource by priority
66
+ @environment_resources = @environment_resources.sort_by { |k| k[:priority]}.reverse
67
+
68
+ @environment_resources.each do |resource|
69
+ $log.info("Stopping resource #{resource[:id]}")
70
+ # just print out information if running a dry run, otherwise start assets
71
+ if not @dry_run
72
+ eval "self.#{resource[:method]}('stop','#{resource[:id]}')"
73
+ else
74
+ $log.info("Dry run enabled, skipping stop start\nFollowing resource would be stopped: #{resource[:id]}")
75
+ $log.debug("Resource type: #{resource[:type]}\n\n")
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ def do_start_assets
82
+ # sort start resource by priority
83
+ @environment_resources = @environment_resources.sort_by { |k| k[:priority]}
84
+
85
+ @environment_resources.each do |resource|
86
+ $log.info("Starting resource #{resource[:id]}")
87
+ # just print out information if running a dry run, otherwise start assets
88
+ if not @dry_run
89
+ eval "self.#{resource[:method]}('start','#{resource[:id]}')"
90
+ else
91
+ $log.info("Dry run enabled, skipping actual start\nFollowing resource would be started: #{resource[:id]}")
92
+ $log.debug("Resource type: #{resource[:type]}\n\n")
93
+ end
94
+ end
95
+ end
96
+
97
+ def collect_resources(stack_name)
98
+ resrouces = @cf_client.describe_stack_resources(stack_name: stack_name)
99
+ 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']]
102
+ resource_id = resource['physical_resource_id']
103
+
104
+ @environment_resources << {
105
+ id: resource_id,
106
+ priority: @@resource_start_priorities[resource['resource_type']],
107
+ method: method_name,
108
+ type: resource['resource_type']
109
+ }
110
+ end
111
+ end
112
+ end
113
+
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
+ configuration = {
263
+ is_multi_az: rds_instance.multi_az
264
+ }
265
+ save_item_configuration(s3_prefix, configuration)
266
+
267
+ #check if mutli-az RDS. if so, convert to single-az
268
+ if rds_instance.multi_az
269
+ $log.info("Converting to Non-Multi-AZ instance before stop (instance #{instance_id}")
270
+ set_rds_instance_multi_az(rds_instance, false)
271
+ end
272
+
273
+ # stop rds instance and wait for it to be fully stopped
274
+ $log.info("Stopping instance #{instance_id}")
275
+ rds_client.stop_db_instance({ db_instance_identifier: instance_id })
276
+ $log.info("Waiting db instance to be stopped #{instance_id}")
277
+ wait_rds_instance_states(rds_client, instance_id, %w(stopping stopped))
278
+ end
279
+ end
280
+
281
+ def set_rds_instance_multi_az(rds_instance, multi_az)
282
+ if rds_instance.multi_az == multi_az
283
+ $log.info("Rds instance #{rds_instance.db_instance_identifier} already multi-az=#{multi_az}")
284
+ return
285
+ end
286
+ rds_instance.modify({ multi_az: multi_az, apply_immediately: true })
287
+ # allow half an hour for instance to be converted
288
+ wait_states = %w(modifying available)
289
+ wait_rds_instance_states(rds_instance, wait_states)
290
+ end
291
+
292
+ def wait_rds_instance_states(client, rds_instance_id, wait_states)
293
+ wait_states.each do |state|
294
+ # reached state must be steady, at least a minute. Modifying an instance to/from MultiAZ can't be shorter
295
+ # than 40 seconds, hence steady count is 4
296
+ state_count = 0
297
+ steady_count = 4
298
+ attempts = 0
299
+ rds = Aws::RDS::Resource.new(client: client)
300
+ until attempts == (max_attempts = 60*6) do
301
+ instance = rds.db_instance(rds_instance_id)
302
+ $log.info("Instance #{instance.db_instance_identifier} state: #{instance.db_instance_status}, waiting for #{state}")
303
+
304
+ if instance.db_instance_status == "#{state}"
305
+ state_count = state_count + 1
306
+ $log.info("#{state_count}/#{steady_count}")
307
+ else
308
+ state_count = 0
309
+ end
310
+ break if state_count == steady_count
311
+ attempts = attempts + 1
312
+ sleep(15)
313
+ end
314
+
315
+ if attempts == max_attempts
316
+ $log.error("RDS Database Instance #{rds_instance_id} did not enter #{state} state, however continuing operations...")
317
+ end
318
+
319
+ end
320
+ end
321
+
322
+
323
+ def get_object_configuration(s3_prefix)
324
+ configuration = nil
325
+ begin
326
+ key = "#{s3_prefix}/latest/config.json"
327
+ $log.info("Reading object configuration from s3://#{@s3_bucket}/#{key}")
328
+
329
+ # fetch and deserialize and s3 object
330
+ configuration = JSON.parse(@s3_client.get_object(bucket: @s3_bucket, key: key).body.read)
331
+
332
+ $log.info("Configuration:#{configuration}")
333
+ rescue Aws::S3::Errors::NoSuchKey
334
+ $log.warn("Could not find configuration at s3://#{@s3_bucket}/#{key}")
335
+ end
336
+ configuration
337
+ end
338
+
339
+ def save_item_configuration(s3_prefix, configuration)
340
+ # save latest configuration, and one time-based versioned
341
+ s3_keys = [
342
+ "#{s3_prefix}/latest/config.json",
343
+ "#{s3_prefix}/#{Time.now.getutc.to_i}/config.json"
344
+ ]
345
+ s3_keys.each do |key|
346
+ $log.info("Saving configuration to #{@s3_bucket}/#{key}\n#{configuration}")
347
+ $log.info(configuration.to_yaml)
348
+ @s3_client.put_object({
349
+ bucket: @s3_bucket,
350
+ key: key,
351
+ body: JSON.pretty_generate(configuration)
352
+ })
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cfn_manage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Base2Services
8
+ - Nikola Tosic
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-09-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws-sdk
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '3'
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '4'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: '3'
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '4'
34
+ description: ''
35
+ email: info@base2services.com
36
+ executables:
37
+ - cfn_manage
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - bin/cfn_manage
42
+ - bin/cfn_manage.rb
43
+ - bin/usage.txt
44
+ - lib/aws_credentials.rb
45
+ - lib/cf_common.rb
46
+ - lib/cf_progress_tracker.rb
47
+ - lib/cf_start_stop_environment.rb
48
+ homepage: http://rubygems.org/gems/cfn_manage
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.6.12
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Manage Cloud Formation stacks
72
+ test_files: []