cfn_manage 0.1.0

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