cfn_manage 0.4.3 → 0.5.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 +5 -5
- data/bin/cfn_manage +157 -1
- data/bin/usage.txt +32 -2
- data/lib/cfn_manage.rb +1 -0
- data/lib/{alarm_start_stop_handler.rb → cfn_manage/alarm_start_stop_handler.rb} +9 -4
- data/lib/{asg_start_stop_handler.rb → cfn_manage/asg_start_stop_handler.rb} +10 -6
- data/lib/{aurora_cluster_start_stop_handler.rb → cfn_manage/aurora_cluster_start_stop_handler.rb} +35 -36
- data/lib/{aws_credentials.rb → cfn_manage/aws_credentials.rb} +2 -2
- data/lib/{cf_common.rb → cfn_manage/cf_common.rb} +1 -1
- data/lib/{cf_progress_tracker.rb → cfn_manage/cf_progress_tracker.rb} +6 -6
- data/lib/{cf_start_stop_environment.rb → cfn_manage/cf_start_stop_environment.rb} +107 -63
- data/lib/{ec2_start_stop_handler.rb → cfn_manage/ec2_start_stop_handler.rb} +9 -7
- data/lib/cfn_manage/ecs_cluster_start_stop_handler.rb +66 -0
- data/lib/{rds_start_stop_handler.rb → cfn_manage/rds_start_stop_handler.rb} +41 -42
- data/lib/{spot_fleet_start_stop_handler.rb → cfn_manage/spot_fleet_start_stop_handler.rb} +10 -6
- data/lib/cfn_manage/start_stop_handler_factory.rb +44 -0
- data/lib/cfn_manage/version.rb +3 -0
- metadata +137 -16
- data/bin/cfn_manage.rb +0 -108
- data/lib/start_stop_handler_factory.rb +0 -39
@@ -1,16 +1,17 @@
|
|
1
|
-
|
1
|
+
require 'cfn_manage/aws_credentials'
|
2
2
|
|
3
|
-
module
|
3
|
+
module CfnManage
|
4
4
|
|
5
5
|
class Ec2StartStopHandler
|
6
6
|
|
7
7
|
@instance
|
8
8
|
|
9
|
-
def initialize(instance_id)
|
10
|
-
credentials =
|
9
|
+
def initialize(instance_id, skip_wait)
|
10
|
+
credentials = CfnManage::AWSCredentials.get_session_credentials("stoprun_#{instance_id}")
|
11
11
|
ec2_client = Aws::EC2::Client.new(credentials: credentials, retry_limit: 20)
|
12
12
|
@instance = Aws::EC2::Resource.new(client: ec2_client, retry_limit: 20).instance(instance_id)
|
13
13
|
@instance_id = instance_id
|
14
|
+
@skip_wait = skip_wait
|
14
15
|
end
|
15
16
|
|
16
17
|
def start(configuration)
|
@@ -34,8 +35,9 @@ module Base2
|
|
34
35
|
return {}
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
def wait(wait_states=[])
|
39
|
+
$log.debug("Not waiting for EC2 instance #{@instance_id}")
|
40
|
+
end
|
39
41
|
|
40
42
|
end
|
41
|
-
end
|
43
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'cfn_manage/aws_credentials'
|
2
|
+
|
3
|
+
module CfnManage
|
4
|
+
class EcsClusterStartStopHandler
|
5
|
+
|
6
|
+
def initialize(cluster_id, skip_wait)
|
7
|
+
credentials = CfnManage::AWSCredentials.get_session_credentials("stoprun_#{cluster_id}")
|
8
|
+
@ecs_client = Aws::ECS::Client.new(credentials: credentials, retry_limit: 20)
|
9
|
+
@services = @ecs_client.list_services(cluster: cluster_id).service_arns
|
10
|
+
$log.info("Found #{@services.count} services in ECS cluster #{cluster_id}")
|
11
|
+
@cluster = cluster_id
|
12
|
+
@skip_wait = skip_wait
|
13
|
+
end
|
14
|
+
|
15
|
+
def start(configuration)
|
16
|
+
@services.each do |service_arn|
|
17
|
+
|
18
|
+
$log.info("Searching for ECS service #{service_arn} in cluster #{@cluster}")
|
19
|
+
service = @ecs_client.describe_services(services:[service_arn], cluster: @cluster).services[0]
|
20
|
+
|
21
|
+
if service.desired_count != 0
|
22
|
+
$log.info("ECS service #{service.service_name} is already running")
|
23
|
+
next
|
24
|
+
end
|
25
|
+
|
26
|
+
$log.info("Starting ECS service #{service.service_name} with desired count of #{configuration[service.service_name]['desired_count']}")
|
27
|
+
@ecs_client.update_service({
|
28
|
+
desired_count: configuration[service.service_name]['desired_count'],
|
29
|
+
service: service_arn,
|
30
|
+
cluster: @cluster
|
31
|
+
})
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
configuration = {}
|
38
|
+
@services.each do |service_arn|
|
39
|
+
|
40
|
+
$log.info("Searching for ECS service #{service_arn} in cluster #{@cluster}")
|
41
|
+
service = @ecs_client.describe_services(services:[service_arn], cluster: @cluster).services[0]
|
42
|
+
|
43
|
+
if service.desired_count == 0
|
44
|
+
$log.info("ECS service #{service.service_name} is already stopped")
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
configuration[service.service_name] = { desired_count: service.desired_count }
|
49
|
+
$log.info("Stopping ECS service #{service.service_name}")
|
50
|
+
@ecs_client.update_service({
|
51
|
+
desired_count: 0,
|
52
|
+
service: service_arn,
|
53
|
+
cluster: @cluster
|
54
|
+
})
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
return configuration
|
59
|
+
end
|
60
|
+
|
61
|
+
def wait(completed_status)
|
62
|
+
$log.debug("Not waiting for ECS Services in cluster #{@cluster}")
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
|
-
|
1
|
+
require 'cfn_manage/aws_credentials'
|
2
2
|
|
3
|
-
module
|
3
|
+
module CfnManage
|
4
4
|
|
5
5
|
class RdsStartStopHandler
|
6
6
|
|
7
|
-
def initialize(instance_id)
|
7
|
+
def initialize(instance_id, skip_wait)
|
8
8
|
@instance_id = instance_id
|
9
|
-
|
10
|
-
|
9
|
+
@skip_wait = skip_wait
|
10
|
+
@excluded_engines = %w(aurora aurora-mysql aurora-postgresql) # RDS list of exluded engines that don't support RDS stop start
|
11
|
+
credentials = CfnManage::AWSCredentials.get_session_credentials("startstoprds_#{instance_id}")
|
11
12
|
@rds_client = Aws::RDS::Client.new(retry_limit: 20)
|
12
13
|
if credentials != nil
|
13
14
|
@rds_client = Aws::RDS::Client.new(credentials: credentials, retry_limit: 20)
|
@@ -18,9 +19,7 @@ module Base2
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def start(configuration)
|
21
|
-
|
22
|
-
excluded_engines = %w(aurora aurora-mysql aurora-postgresql)
|
23
|
-
if excluded_engines.include? @rds_instance.engine
|
22
|
+
if @excluded_engines.include? @rds_instance.engine
|
24
23
|
$log.info("RDS Instance #{@instance_id} engine is #{@rds_instance.engine} and cannot be started by instance.")
|
25
24
|
return
|
26
25
|
end
|
@@ -35,10 +34,12 @@ module Base2
|
|
35
34
|
@rds_client.start_db_instance({ db_instance_identifier: @instance_id })
|
36
35
|
|
37
36
|
# wait instance to become available
|
38
|
-
|
39
|
-
|
37
|
+
unless @skip_wait
|
38
|
+
$log.info("Waiting db instance to become available #{@instance_id}")
|
39
|
+
wait('available')
|
40
|
+
end
|
40
41
|
else
|
41
|
-
|
42
|
+
wait('available') unless @skip_wait
|
42
43
|
end
|
43
44
|
|
44
45
|
# convert rds instance to mutli-az if required
|
@@ -54,8 +55,7 @@ module Base2
|
|
54
55
|
is_multi_az: @rds_instance.multi_az
|
55
56
|
}
|
56
57
|
# RDS list of exluded engines that don't support RDS stop start
|
57
|
-
excluded_engines
|
58
|
-
if excluded_engines.include? @rds_instance.engine
|
58
|
+
if @excluded_engines.include? @rds_instance.engine
|
59
59
|
$log.info("RDS Instance #{@instance_id} engine is #{@rds_instance.engine} and cannot be stoped by instance.")
|
60
60
|
return configuration
|
61
61
|
end
|
@@ -82,8 +82,10 @@ module Base2
|
|
82
82
|
# stop rds instance and wait for it to be fully stopped
|
83
83
|
$log.info("Stopping instance #{@instance_id}")
|
84
84
|
@rds_client.stop_db_instance({ db_instance_identifier: @instance_id })
|
85
|
-
|
86
|
-
|
85
|
+
unless @skip_wait
|
86
|
+
$log.info("Waiting db instance to be stopped #{@instance_id}")
|
87
|
+
wait('stopped')
|
88
|
+
end
|
87
89
|
|
88
90
|
return configuration
|
89
91
|
end
|
@@ -95,40 +97,37 @@ module Base2
|
|
95
97
|
end
|
96
98
|
@rds_instance.modify({ multi_az: multi_az, apply_immediately: true })
|
97
99
|
# allow half an hour for instance to be converted
|
98
|
-
|
99
|
-
wait_rds_instance_states( wait_states)
|
100
|
+
wait('available')
|
100
101
|
end
|
101
102
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
state_count = 0
|
119
|
-
end
|
120
|
-
break if state_count == steady_count
|
121
|
-
attempts = attempts + 1
|
122
|
-
sleep(15)
|
103
|
+
def wait(completed_state)
|
104
|
+
# reached state must be steady, at least a minute. Modifying an instance to/from MultiAZ can't be shorter
|
105
|
+
# than 40 seconds, hence steady count is 4
|
106
|
+
state_count = 0
|
107
|
+
steady_count = 4
|
108
|
+
attempts = 0
|
109
|
+
rds = Aws::RDS::Resource.new(client: @rds_client)
|
110
|
+
until attempts == (max_attempts = 60*6) do
|
111
|
+
instance = rds.db_instance(@instance_id)
|
112
|
+
$log.info("Instance #{instance.db_instance_identifier} state: #{instance.db_instance_status}, waiting for #{completed_state}")
|
113
|
+
|
114
|
+
if instance.db_instance_status == "#{completed_state}"
|
115
|
+
state_count = state_count + 1
|
116
|
+
$log.info("#{state_count}/#{steady_count}")
|
117
|
+
else
|
118
|
+
state_count = 0
|
123
119
|
end
|
120
|
+
break if state_count == steady_count
|
121
|
+
attempts = attempts + 1
|
122
|
+
sleep(15)
|
123
|
+
end
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
end
|
125
|
+
if attempts == max_attempts
|
126
|
+
$log.error("RDS Database Instance #{@instance_id} did not enter #{state} state, however continuing operations...")
|
128
127
|
end
|
129
128
|
end
|
130
129
|
|
131
|
-
private :set_rds_instance_multi_az
|
130
|
+
private :set_rds_instance_multi_az
|
132
131
|
|
133
132
|
end
|
134
133
|
|
@@ -1,13 +1,13 @@
|
|
1
|
-
|
1
|
+
require 'cfn_manage/aws_credentials'
|
2
2
|
|
3
|
-
module
|
3
|
+
module CfnManage
|
4
4
|
|
5
5
|
class SpotFleetStartStopHandler
|
6
6
|
|
7
|
-
def initialize(fleet_id)
|
7
|
+
def initialize(fleet_id, skip_wait)
|
8
8
|
@fleet_id = fleet_id
|
9
|
-
|
10
|
-
credentials =
|
9
|
+
@skip_wait = skip_wait
|
10
|
+
credentials = CfnManage::AWSCredentials.get_session_credentials("startstopfleet_#{fleet_id}")
|
11
11
|
@ec2_client = Aws::EC2::Client.new(retry_limit: 20)
|
12
12
|
if credentials != nil
|
13
13
|
@ec2_client = Aws::EC2::Client.new(credentials: credentials, retry_limit: 20)
|
@@ -48,6 +48,10 @@ module Base2
|
|
48
48
|
return configuration
|
49
49
|
end
|
50
50
|
|
51
|
+
def wait(wait_states=[])
|
52
|
+
$log.debug("Not waiting for spot fleet #{@fleet_id}")
|
53
|
+
end
|
54
|
+
|
51
55
|
end
|
52
56
|
|
53
|
-
end
|
57
|
+
end
|
@@ -0,0 +1,44 @@
|
|
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
|
+
|
9
|
+
module CfnManage
|
10
|
+
|
11
|
+
class StartStopHandlerFactory
|
12
|
+
|
13
|
+
# Factory method to get start/stop handler based on CloudFormation
|
14
|
+
# resource type. If resource_id passed in does not exist, it is
|
15
|
+
# very likely that exception will be raised
|
16
|
+
def self.get_start_stop_handler(resource_type, resource_id, skip_wait)
|
17
|
+
case resource_type
|
18
|
+
when 'AWS::AutoScaling::AutoScalingGroup'
|
19
|
+
return CfnManage::AsgStartStopHandler.new(resource_id, skip_wait)
|
20
|
+
|
21
|
+
when 'AWS::EC2::Instance'
|
22
|
+
return CfnManage::Ec2StartStopHandler.new(resource_id, skip_wait)
|
23
|
+
|
24
|
+
when 'AWS::RDS::DBInstance'
|
25
|
+
return CfnManage::RdsStartStopHandler.new(resource_id, skip_wait)
|
26
|
+
|
27
|
+
when 'AWS::RDS::DBCluster'
|
28
|
+
return CfnManage::AuroraClusterStartStopHandler.new(resource_id, skip_wait)
|
29
|
+
|
30
|
+
when 'AWS::CloudWatch::Alarm'
|
31
|
+
return CfnManage::AlarmStartStopHandler.new(resource_id)
|
32
|
+
|
33
|
+
when 'AWS::EC2::SpotFleet'
|
34
|
+
return CfnManage::SpotFleetStartStopHandler.new(resource_id, skip_wait)
|
35
|
+
|
36
|
+
when 'AWS::ECS::Cluster'
|
37
|
+
return CfnManage::EcsClusterStartStopHandler.new(resource_id, skip_wait)
|
38
|
+
|
39
|
+
else
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfn_manage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Base2Services
|
8
8
|
- Nikola Tosic
|
9
|
+
- Angus Vine
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2018-10-
|
13
|
+
date: 2018-10-26 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: aws-sdk-core
|
@@ -171,6 +172,124 @@ dependencies:
|
|
171
172
|
- - "<"
|
172
173
|
- !ruby/object:Gem::Version
|
173
174
|
version: '2'
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: aws-sdk-ecs
|
177
|
+
requirement: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "~>"
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '1'
|
182
|
+
- - "<"
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '2'
|
185
|
+
type: :runtime
|
186
|
+
prerelease: false
|
187
|
+
version_requirements: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - "~>"
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '1'
|
192
|
+
- - "<"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '2'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: bundler
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '1.16'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '1.16'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rake
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '10.0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '10.0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: rspec
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - "~>"
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0.9'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - "~>"
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0.9'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: rspec-core
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - "~>"
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '3.8'
|
244
|
+
type: :development
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - "~>"
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '3.8'
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: rspec-expectations
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - "~>"
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '3.8'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - "~>"
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '3.8'
|
265
|
+
- !ruby/object:Gem::Dependency
|
266
|
+
name: rspec-mocks
|
267
|
+
requirement: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - "~>"
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '3.8'
|
272
|
+
type: :development
|
273
|
+
prerelease: false
|
274
|
+
version_requirements: !ruby/object:Gem::Requirement
|
275
|
+
requirements:
|
276
|
+
- - "~>"
|
277
|
+
- !ruby/object:Gem::Version
|
278
|
+
version: '3.8'
|
279
|
+
- !ruby/object:Gem::Dependency
|
280
|
+
name: simplecov
|
281
|
+
requirement: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - "~>"
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '0.16'
|
286
|
+
type: :development
|
287
|
+
prerelease: false
|
288
|
+
version_requirements: !ruby/object:Gem::Requirement
|
289
|
+
requirements:
|
290
|
+
- - "~>"
|
291
|
+
- !ruby/object:Gem::Version
|
292
|
+
version: '0.16'
|
174
293
|
description: ''
|
175
294
|
email: itsupport@base2services.com
|
176
295
|
executables:
|
@@ -179,20 +298,22 @@ extensions: []
|
|
179
298
|
extra_rdoc_files: []
|
180
299
|
files:
|
181
300
|
- bin/cfn_manage
|
182
|
-
- bin/cfn_manage.rb
|
183
301
|
- bin/usage.txt
|
184
|
-
- lib/
|
185
|
-
- lib/
|
186
|
-
- lib/
|
187
|
-
- lib/
|
188
|
-
- lib/
|
189
|
-
- lib/
|
190
|
-
- lib/
|
191
|
-
- lib/
|
192
|
-
- lib/
|
193
|
-
- lib/
|
194
|
-
- lib/
|
195
|
-
|
302
|
+
- lib/cfn_manage.rb
|
303
|
+
- lib/cfn_manage/alarm_start_stop_handler.rb
|
304
|
+
- lib/cfn_manage/asg_start_stop_handler.rb
|
305
|
+
- lib/cfn_manage/aurora_cluster_start_stop_handler.rb
|
306
|
+
- lib/cfn_manage/aws_credentials.rb
|
307
|
+
- lib/cfn_manage/cf_common.rb
|
308
|
+
- lib/cfn_manage/cf_progress_tracker.rb
|
309
|
+
- lib/cfn_manage/cf_start_stop_environment.rb
|
310
|
+
- lib/cfn_manage/ec2_start_stop_handler.rb
|
311
|
+
- lib/cfn_manage/ecs_cluster_start_stop_handler.rb
|
312
|
+
- lib/cfn_manage/rds_start_stop_handler.rb
|
313
|
+
- lib/cfn_manage/spot_fleet_start_stop_handler.rb
|
314
|
+
- lib/cfn_manage/start_stop_handler_factory.rb
|
315
|
+
- lib/cfn_manage/version.rb
|
316
|
+
homepage: https://github.com/base2Services/cfn-start-stop-stack/blob/master/README.md
|
196
317
|
licenses:
|
197
318
|
- MIT
|
198
319
|
metadata: {}
|
@@ -212,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
333
|
version: '0'
|
213
334
|
requirements: []
|
214
335
|
rubyforge_project:
|
215
|
-
rubygems_version: 2.
|
336
|
+
rubygems_version: 2.7.7
|
216
337
|
signing_key:
|
217
338
|
specification_version: 4
|
218
339
|
summary: Manage AWS Cloud Formation stacks
|