cloudstrap 0.40.6.pre → 0.41.0.pre

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
  SHA1:
3
- metadata.gz: 5a5bf4cc062a88716ec4b3de1d0017d1bf18b9a2
4
- data.tar.gz: 2712602daa177346ec20ee45eb9ca0f3aa3cd977
3
+ metadata.gz: 50dc8355b21605ab2efa9d6b50ef736790aef7cd
4
+ data.tar.gz: fa0935623212f01051ce772e926998f11e7af097
5
5
  SHA512:
6
- metadata.gz: fa9c055e4b02276ce392209ebca8f8559d3e48f13eaa46f8caaf00632e286e88acf329c7c1e366f13bef464c6334cfec50de79b808b57ceef25416d895d47a97
7
- data.tar.gz: c54a863569ecc78708d9ee560f5169a8c3674469f1b915fb227fc9d2aef563b57f615217f3dcad61c9fbadc867357b9813559aa8a7ad55629b018f40f6ef4f15
6
+ metadata.gz: 8c3056ac6b788d62c78abae32e2a4a6d3567ed02d0b0701308ac7e18d2916b4f1cd86e8881c7cdab6db8ee6ab63d77edca826b35e82f9185988723ccaafb2df1
7
+ data.tar.gz: edb1a9a3b503d94cbb226d3ecdee5fe53878a036dc1334453df12c8f5982cf2c97d8d5a3ce86c6cb1df5009583ea246a39a23582b2ef8fda94c17b921c154213
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort 'usage: cloudstrap-teardown <vpc>' if ARGV.empty?
4
+
5
+ require 'aws-sdk'
6
+ require 'concurrent'
7
+ require 'tty/spinner'
8
+
9
+ ARBITRARY_DELAY_TO_PLEASE_THE_EYES = (0.8..1.2)
10
+
11
+ spinner = ->(s) { TTY::Spinner.new "[:spinner] #{s} ...", format: :arrow_pulse }
12
+
13
+ show = lambda do |text, &block|
14
+ Concurrent::IVar.new.tap do |ivar|
15
+ spinner.(text).run('done!') do
16
+ ivar.set block.call
17
+ end
18
+ end.value
19
+ end
20
+
21
+ def wait_a_bit
22
+ sleep rand ARBITRARY_DELAY_TO_PLEASE_THE_EYES
23
+ end
24
+
25
+ def user_wants_to_go_fast?
26
+ true unless %w(false nil).include? ENV.fetch('CLOUDSTRAP_GO_ZOOM') { 'false' }
27
+ end
28
+
29
+ ##
30
+ # AWS Resources are lazy by nature.
31
+ ##
32
+
33
+ eager = lambda do |method, object|
34
+ if object.respond_to? :flat_map
35
+ object.flat_map(&eager.(method))
36
+ else
37
+ object.public_send(method).map(&:itself)
38
+ end
39
+ end.curry
40
+
41
+ ##
42
+ # Explore VPC
43
+ ##
44
+
45
+ task = {}
46
+
47
+ task[:vpcs] = Concurrent.dataflow do
48
+ show.('Discovering VPCs') do
49
+ Aws::EC2::Resource.new.vpcs.select { |vpc| ARGV.include? vpc.id }
50
+ end
51
+ end
52
+
53
+ wait_a_bit unless user_wants_to_go_fast?
54
+
55
+ task[:internet_gateways] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
56
+ show.("Discovering Internet Gateways in #{vpcs.size} VPCs") do
57
+ eager.(:internet_gateways).(vpcs)
58
+ end
59
+ end
60
+
61
+ wait_a_bit unless user_wants_to_go_fast?
62
+
63
+ task[:instances] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
64
+ show.("Discovering Instances in #{vpcs.size} VPCs") do
65
+ eager.(:instances).(vpcs)
66
+ end
67
+ end
68
+
69
+ wait_a_bit unless user_wants_to_go_fast?
70
+
71
+ task[:subnets] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
72
+ show.("Discovering Subnets in #{vpcs.size} VPCs") do
73
+ eager.(:subnets).(vpcs)
74
+ end
75
+ end
76
+
77
+ wait_a_bit unless user_wants_to_go_fast?
78
+
79
+ task[:security_groups] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
80
+ show.("Discovering Security Groups in #{vpcs.size} VPCs") do
81
+ eager.(:security_groups).(vpcs)
82
+ end
83
+ end
84
+
85
+ wait_a_bit unless user_wants_to_go_fast?
86
+
87
+ task[:route_tables] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
88
+ show.("Discovering Route Tables in #{vpcs.size} VPCs") do
89
+ eager.(:instances).(vpcs)
90
+ end
91
+ end
92
+
93
+ wait_a_bit unless user_wants_to_go_fast?
94
+
95
+ task[:routes] = Concurrent.dataflow(task[:route_tables]) do |route_tables|
96
+ show.("Discovering Routes in #{route_tables.size} Route Tables") do
97
+ eager.(:routes).(route_tables)
98
+ end
99
+ end
100
+
101
+ wait_a_bit unless user_wants_to_go_fast?
102
+
103
+ task[:sg_ingress_rules] = Concurrent.dataflow(task[:security_groups]) do |security_groups|
104
+ show.("Discovering Ingress Rules in #{security_groups.size} Security Groups") do
105
+ security_groups.map do |security_group|
106
+ ingress_rules = security_group.ip_permissions.map(&:to_h).map do |rule|
107
+ rule.reject { |_, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }
108
+ end
109
+ [security_group, ingress_rules]
110
+ end.to_h
111
+ end
112
+ end
113
+
114
+ wait_a_bit unless user_wants_to_go_fast?
115
+
116
+ task[:sg_egress_rules] = Concurrent.dataflow(task[:security_groups]) do |security_groups|
117
+ show.("Discovering Egress Rules in #{security_groups.size} Security Groups") do
118
+ security_groups.map do |security_group|
119
+ egress_rules = security_group.ip_permissions_egress.map(&:to_h).map do |rule|
120
+ rule.reject { |_, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }
121
+ end
122
+ [security_group, egress_rules]
123
+ end.to_h
124
+ end
125
+ end
126
+
127
+ wait_a_bit unless user_wants_to_go_fast?
128
+
129
+ task[:nat_gateways] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
130
+ show.("Discovering NAT Gateways in #{vpcs.size} VPCs") do
131
+ query = Aws::EC2::Client.new.describe_nat_gateways
132
+ (query.successful? ? query.nat_gateways : [])
133
+ .select { |ngw| vpcs.any? { |vpc| ngw.vpc_id == vpc.id } }
134
+ end
135
+ end
136
+
137
+ wait_a_bit unless user_wants_to_go_fast?
138
+
139
+ task[:classic_elbs] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
140
+ show.("Discovering Classic Load Balancers in #{vpcs.size} VPCs") do
141
+ query = Aws::ElasticLoadBalancing::Client.new.describe_load_balancers
142
+ (query.successful? ? query.load_balancer_descriptions : [])
143
+ .select { |elb| vpcs.any? { |vpc| elb.vpc_id == vpc.id } }
144
+ end
145
+ end
146
+
147
+ wait_a_bit unless user_wants_to_go_fast?
148
+
149
+ task[:application_elbs] = Concurrent.dataflow(task[:vpcs]) do |vpcs|
150
+ show.("Discovering Application Load Balancers in #{vpcs.size} VPCs") do
151
+ query = Aws::ElasticLoadBalancingV2::Client.new.describe_load_balancers
152
+ (query.successful? ? query.load_balancers : [])
153
+ .select { |elb| vpcs.any? { |vpc| elb.vpc_id == vpc.id } }
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Burn it to the ground
159
+ ##
160
+
161
+ wait_a_bit unless user_wants_to_go_fast?
162
+
163
+ task[:instances_relocated] = Concurrent.dataflow(task[:instances], task[:security_groups]) do |instances, security_groups|
164
+ show.("Relocating #{instances.size} Instances to #{security_groups.size} Default Security Groups") do
165
+ instances.map do |instance|
166
+ default = security_groups
167
+ .select { |sg| sg.vpc_id == instance.vpc_id }
168
+ .find { |sg| sg.group_name == 'default' }
169
+ instance.modify_attribute groups: [default.id]
170
+ end
171
+ end
172
+ end
173
+
174
+ wait_a_bit unless user_wants_to_go_fast?
175
+
176
+ task[:nat_gateways_deleted] = Concurrent.dataflow(task[:nat_gateways]) do |gateways|
177
+ show.("Deleting #{gateways.size} NAT Gateways") do
178
+ gateways.map do |ngw|
179
+ Aws::EC2::Client.new.delete_nat_gateway nat_gateway_id: ngw.nat_gateway_id
180
+ end
181
+ end
182
+ end
183
+
184
+ wait_a_bit unless user_wants_to_go_fast?
185
+
186
+ task[:instances_terminated] = Concurrent.dataflow(task[:instances], task[:instances_relocated]) do |instances|
187
+ show.("Terminating #{instances.size} Instances") do
188
+ instances.each(&:terminate).map(&:wait_until_terminated)
189
+ end
190
+ end
191
+
192
+ wait_a_bit unless user_wants_to_go_fast?
193
+
194
+ task[:igw_detached] = Concurrent.dataflow(task[:internet_gateways], task[:instances_terminated], task[:nat_gateways_deleted]) do |gateways|
195
+ show.("Detaching #{gateways.size} Internet Gateways") do
196
+ gateways.map do |igw|
197
+ igw.attachments.map(&:vpc_id).map do |vpc|
198
+ igw.detach_from_vpc vpc_id: vpc
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ wait_a_bit unless user_wants_to_go_fast?
205
+
206
+ task[:igw_deleted] = Concurrent.dataflow(task[:internet_gateways], task[:igw_detached]) do |gateways|
207
+ show.("Deleting #{gateways.size} Internet Gateways") do
208
+ gateways.map(&:delete)
209
+ end
210
+ end
211
+
212
+ wait_a_bit unless user_wants_to_go_fast?
213
+
214
+ task[:sg_ingress_revoked] = Concurrent.dataflow(task[:sg_ingress_rules]) do |ingress|
215
+ count = ingress.values.map(&:size).reduce(:+)
216
+ show.("Revoking #{count} Ingress Rules for Security Groups") do
217
+ ingress.map do |sg, rules|
218
+ sg.revoke_ingress ip_permissions: rules unless rules.empty?
219
+ end
220
+ end
221
+ end
222
+
223
+ wait_a_bit unless user_wants_to_go_fast?
224
+
225
+ task[:sg_egress_revoked] = Concurrent.dataflow(task[:sg_egress_rules]) do |egress|
226
+ count = egress.values.map(&:size).reduce(:+)
227
+ show.("Revoking #{count} Egress Rules for Security Groups") do
228
+ egress.map do |sg, rules|
229
+ sg.revoke_egress ip_permissions: rules unless rules.empty?
230
+ end
231
+ end
232
+ end
233
+
234
+ wait_a_bit unless user_wants_to_go_fast?
235
+
236
+ task[:security_groups_deleted] = Concurrent.dataflow(task[:security_groups], task[:sg_ingress_revoked], task[:sg_egress_revoked]) do |all_security_groups|
237
+ security_groups = all_security_groups.reject { |sg| sg.group_name == 'default' }
238
+ show.("Deleting #{security_groups.size} Security Groups") do
239
+ security_groups.map(&:delete)
240
+ end
241
+ end
242
+
243
+ wait_a_bit unless user_wants_to_go_fast?
244
+
245
+ task[:subnets_deleted] = Concurrent.dataflow(task[:subnets]) do |subnets|
246
+ show.("Deleting #{subnets.size} Subnets") do
247
+ subnets.map(&:delete)
248
+ end
249
+ end
250
+
251
+ wait_a_bit unless user_wants_to_go_fast?
252
+
253
+ task[:routes_deleted] = Concurrent.dataflow(task[:routes]) do |all_routes|
254
+ routes = all_routes.reject { |route| route.gateway_id == 'local' }
255
+ show.("Deleting #{routes.size} Routes") do
256
+ routes.each(&:delete)
257
+ end
258
+ end
259
+
260
+ wait_a_bit unless user_wants_to_go_fast?
261
+
262
+ vpcs_deleted = Concurrent.dataflow(task[:vpcs], *task.values) do |vpcs|
263
+ show.("Deleting #{vpcs.size} VPCs") do
264
+ vpcs.map do |vpc|
265
+ begin
266
+ vpc.delete
267
+ rescue Aws::EC2::Errors::DependencyViolation => e
268
+ e
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ puts vpcs_deleted.value
data/cloudstrap.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |gem|
20
20
  gem.add_runtime_dependency 'sshkit', '~> 1.11', '>= 1.11.0'
21
21
  gem.add_runtime_dependency 'java-properties', '~> 0.1', '>= 0.1.1'
22
22
  gem.add_runtime_dependency 'pastel', '~> 0.6', '>= 0.6.0'
23
+ gem.add_runtime_dependency 'tty-spinner', '~> 0.4', '>= 0.4.1'
23
24
  gem.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.0'
24
25
  gem.add_runtime_dependency 'burdened-acrobat', '~> 0.3', '>= 0.3.4'
25
26
  gem.add_runtime_dependency 'path53', '~> 0.4', '>= 0.4.8'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.40.6.pre
4
+ version: 0.41.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Olstrom
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-14 00:00:00.000000000 Z
11
+ date: 2016-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -170,6 +170,26 @@ dependencies:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
172
  version: 0.6.0
173
+ - !ruby/object:Gem::Dependency
174
+ name: tty-spinner
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '0.4'
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: 0.4.1
183
+ type: :runtime
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '0.4'
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 0.4.1
173
193
  - !ruby/object:Gem::Dependency
174
194
  name: faraday
175
195
  requirement: !ruby/object:Gem::Requirement
@@ -255,6 +275,7 @@ email: chris@olstrom.com
255
275
  executables:
256
276
  - cloudstrap
257
277
  - cloudstrap-dns
278
+ - cloudstrap-teardown
258
279
  extensions: []
259
280
  extra_rdoc_files: []
260
281
  files:
@@ -263,6 +284,7 @@ files:
263
284
  - README.org
264
285
  - bin/cloudstrap
265
286
  - bin/cloudstrap-dns
287
+ - bin/cloudstrap-teardown
266
288
  - cloudstrap.gemspec
267
289
  - lib/cloudstrap.rb
268
290
  - lib/cloudstrap/agent.rb