cloudstrap 0.38.17.pre → 0.38.18.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d4b381bdb8dd6500760236de3105bee2da803ec
4
- data.tar.gz: 9fb538832b1b614c90badb2590b26952ed3c317e
3
+ metadata.gz: e225f883484d21b430decd880534f0e8cc196b80
4
+ data.tar.gz: 9e7908b34eaf90065b1ab9c06bb2a49412e20b12
5
5
  SHA512:
6
- metadata.gz: a1ce90d3b6f056b0929e20e69d5930fe5657450588fa00571bcd8d7953c95a4fe4bf6f65fbe4cc599da1ff61881d3377318c2f476662934dc8eed22a789cee9a
7
- data.tar.gz: 0ce9eb6abf436d78ea4c6391060d3da4b009b24a51b1b8cbf5787f42e0e89215d6c65495b6f56104d31698499e84fae79d02e9894f0d25cb532ced2c2ff24226
6
+ metadata.gz: 83fcf8b3e5ac45584630e45f3bfc24f072498f7d1c6cb606cd9ecfa023a5b70e4aa849f7a72bb8429be409ce6cfade80433d6b9555056cfd22f5a7446855e5fb
7
+ data.tar.gz: 0e210538168f4f7136ad6d25f9c85b8cdd6992433f3da080694994e34c054b29fd0b93c93597581eb1fb2a9edc167ccd70e67dd8e18d9e77e2debd8949cb8331
data/bin/cloudstrap CHANGED
@@ -14,7 +14,7 @@ gem = Gem::Specification
14
14
  .last
15
15
 
16
16
  config = Cloudstrap::Config.new
17
- agent = Cloudstrap::BootstrapAgent.new
17
+ agent = Cloudstrap::Agent.new
18
18
 
19
19
  puts <<-EOS
20
20
  # #{gem.name} v#{gem.version}
data/lib/cloudstrap.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative 'cloudstrap/agent'
1
2
  require_relative 'cloudstrap/amazon'
2
3
  require_relative 'cloudstrap/bootstrap_agent'
3
4
  require_relative 'cloudstrap/config'
@@ -0,0 +1,498 @@
1
+ require 'contracts'
2
+ require 'moneta'
3
+ require 'securerandom'
4
+
5
+ require_relative 'amazon'
6
+ require_relative 'config'
7
+ require_relative 'errors'
8
+ require_relative 'hdp/bootstrap_properties'
9
+ require_relative 'ssh'
10
+
11
+ module Cloudstrap
12
+ class Agent
13
+ include ::Contracts::Core
14
+ include ::Contracts::Builtin
15
+
16
+ Contract None => Agent
17
+ def initialize
18
+ validate_configuration!
19
+ self
20
+ end
21
+
22
+ Contract None => Any
23
+ def validate_configuration! # TODO: Does this really belong in Agent?
24
+ return if ec2.valid_region?(config.region)
25
+ raise ::Cloudstrap::ConfigurationError, "Region #{config.region} is not valid"
26
+ end
27
+
28
+ Contract None => String
29
+ def create_vpc
30
+ cache.store(:vpc_id, ec2.create_vpc.vpc_id).tap do |vpc_id|
31
+ ec2.assign_name(bootstrap_tag, vpc_id)
32
+ end
33
+ end
34
+
35
+ Contract None => Maybe[String]
36
+ def find_vpc
37
+ ENV.fetch('BOOTSTRAP_VPC_ID') do
38
+ cache.fetch(:vpc_id) do
39
+ cache.store :vpc_id, ec2
40
+ .tagged(type: 'vpc', value: bootstrap_tag)
41
+ .map(&:resource_id)
42
+ .first
43
+ end
44
+ end
45
+ end
46
+
47
+ Contract None => String
48
+ def internet_gateway
49
+ find_internet_gateway || create_internet_gateway
50
+ end
51
+
52
+ Contract None => String
53
+ def create_internet_gateway
54
+ cache.store(:internet_gateway_id,
55
+ ec2.create_internet_gateway.internet_gateway_id
56
+ ).tap { |internet_gateway_id| ec2.assign_name bootstrap_tag, internet_gateway_id }
57
+ end
58
+
59
+ Contract None => String
60
+ def nat_gateway_ip_allocation
61
+ ENV.fetch('BOOTSTRAP_NAT_GATEWAY_ALLOCATION_ID') do
62
+ cache.fetch(:nat_gateway_allocation_id) do # TODO: Simplify this.
63
+ id = ec2
64
+ .nat_gateways
65
+ .select { |nat_gateway| nat_gateway.vpc_id == vpc }
66
+ .flat_map { |nat_gateway| nat_gateway.nat_gateway_addresses.map { |address| address.allocation_id } }
67
+ .first || ec2.unassociated_address || ec2.create_address
68
+ cache.store(:nat_gateway_allocation_id, id)
69
+ end
70
+ end
71
+ end
72
+
73
+ Contract None => Maybe[String]
74
+ def find_nat_gateway
75
+ ec2
76
+ .nat_gateways
77
+ .select { |nat_gateway| nat_gateway.vpc_id == vpc }
78
+ .reject { |nat_gateway| %w(failed deleted).include? nat_gateway.state }
79
+ .map { |nat_gateway| nat_gateway.nat_gateway_id }
80
+ .first
81
+ end
82
+
83
+ Contract None => String
84
+ def create_nat_gateway
85
+ attach_gateway unless ec2.internet_gateway_attached?(internet_gateway, vpc)
86
+ ec2.create_nat_gateway(public_subnet, nat_gateway_ip_allocation).nat_gateway_id
87
+ end
88
+
89
+ Contract None => String
90
+ def nat_gateway
91
+ ENV.fetch('BOOTSTRAP_NAT_GATEWAY_ID') do
92
+ cache.fetch(:nat_gateway_id) do
93
+ cache.store(:nat_gateway_id, (find_nat_gateway || create_nat_gateway))
94
+ end
95
+ end
96
+ end
97
+
98
+ Contract None => Maybe[String]
99
+ def find_internet_gateway
100
+ ENV.fetch('BOOTSTRAP_INTERNET_GATEWAY_ID') do
101
+ cache.fetch(:internet_gateway_id) do
102
+ find_tagged_internet_gateway || find_internet_gateway_for_vpc
103
+ end
104
+ end
105
+ end
106
+
107
+ Contract None => Maybe[String]
108
+ def find_tagged_internet_gateway
109
+ ec2
110
+ .tagged(type: 'internet-gateway', value: bootstrap_tag)
111
+ .map { |resource| resource.resource.id }
112
+ .first
113
+ end
114
+
115
+ Contract None => Maybe[String]
116
+ def find_internet_gateway_for_vpc
117
+ ec2
118
+ .internet_gateways
119
+ .select { |gateway| gateway.attachments.any? { |attachment| attachment.vpc_id == vpc } }
120
+ .map { |gateway| gateway.internet_gateway_id }
121
+ .first
122
+ end
123
+
124
+ Contract None => String
125
+ def create_jumpbox_security_group
126
+ cache.store(:jumpbox_security_group, ec2.create_security_group(:jumpbox, vpc)).tap do |sg|
127
+ ec2.assign_name(bootstrap_tag, sg)
128
+ end
129
+ end
130
+
131
+ Contract None => Maybe[String]
132
+ def find_jumpbox_security_group
133
+ @jumpbox_security_group ||= ENV.fetch('BOOTSTRAP_JUMPBOX_SECURITY_GROUP') do
134
+ cache.fetch(:jumpbox_security_group) do
135
+ cache.store :jumpbox_security_group, ec2
136
+ .tagged(type: 'security-group', value: bootstrap_tag)
137
+ .map(&:resource_id)
138
+ .first
139
+ end
140
+ end
141
+ end
142
+
143
+ Contract None => Bool
144
+ def allow_ssh
145
+ ec2.authorize_security_group_ingress :tcp, 22, '0.0.0.0/0', jumpbox_security_group
146
+ end
147
+
148
+ Contract None => String
149
+ def jumpbox_security_group
150
+ find_jumpbox_security_group || create_jumpbox_security_group
151
+ end
152
+
153
+ Contract None => String
154
+ def private_subnet
155
+ @private_subnet ||= ENV.fetch('BOOTSTRAP_PRIVATE_SUBNET_ID') do
156
+ cache.fetch(:private_subnet_id) do
157
+ properties = { vpc_id: vpc, cidr_block: config.private_cidr_block }
158
+ cache.store(:private_subnet_id, (ec2.subnet(properties) || ec2.create_subnet(properties)).tap do |subnet|
159
+ ec2.assign_name bootstrap_tag, subnet.subnet_id unless subnet.tags.any? do |tag|
160
+ tag.key == 'Name' && tag.value = bootstrap_tag
161
+ end
162
+ end.subnet_id)
163
+ end
164
+ end
165
+ end
166
+
167
+ Contract None => String
168
+ def public_subnet
169
+ @public_subnet ||= ENV.fetch('BOOTSTRAP_PUBLIC_SUBNET_ID') do
170
+ cache.fetch(:public_subnet_id) do
171
+ properties = { vpc_id: vpc, cidr_block: config.public_cidr_block }
172
+ cache.store(:public_subnet_id, (ec2.subnet(properties) || ec2.create_subnet(properties)).tap do |subnet|
173
+ ec2.assign_name bootstrap_tag, subnet.subnet_id unless subnet.tags.any? do |tag|
174
+ tag.key == 'Name' && tag.value = bootstrap_tag
175
+ end
176
+ end.subnet_id)
177
+ end
178
+ end
179
+ end
180
+
181
+ Contract None => String
182
+ def route_table
183
+ @route_table ||= ENV.fetch('BOOTSTRAP_ROUTE_TABLE_ID') do
184
+ cache.fetch(:route_table_id) do
185
+ cache.store(:route_table_id, ec2
186
+ .route_tables
187
+ .select { |route_table| route_table.vpc_id == vpc }
188
+ .select { |route_table| route_table.associations.any? { |association| association.main } }
189
+ .map { |route_table| route_table.route_table_id }
190
+ .first).tap do |route_table_id|
191
+ ec2.assign_name bootstrap_tag, route_table_id
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ Contract None => String
198
+ def private_route_table
199
+ @private_route_table ||= ENV.fetch('BOOTSTRAP_PRIVATE_ROUTE_TABLE_ID') do
200
+ cache.fetch(:private_route_table_id) do
201
+ id = ec2
202
+ .route_tables
203
+ .select { |route_table| route_table.vpc_id == vpc }
204
+ .reject { |route_table| route_table.associations.any? { |association| association.main } }
205
+ .map { |route_table| route_table.route_table_id }
206
+ .first || ec2.create_route_table(vpc).route_table_id
207
+ cache.store(:private_route_table_id, id).tap do |private_route_table_id|
208
+ ec2.assign_name bootstrap_tag, private_route_table_id
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ Contract None => Bool
215
+ def attach_gateway
216
+ ec2.attach_internet_gateway internet_gateway, vpc # TODO: Cache this
217
+ end
218
+
219
+ Contract None => Bool
220
+ def default_route
221
+ ec2.create_route('0.0.0.0/0', internet_gateway, route_table) # TODO: Cache this
222
+ end
223
+
224
+ Contract None => Bool
225
+ def nat_route
226
+ ec2.create_route('0.0.0.0/0', nat_gateway, private_route_table) # TODO: Cache this
227
+ end
228
+
229
+ Contract None => String
230
+ def nat_route_association
231
+ @nat_route_association || ENV.fetch('BOOTSTRAP_NAT_ROUTE_ASSOCIATION_ID') do
232
+ cache.fetch(:nat_route_association_id) do
233
+ cache.store(:nat_route_association_id, ec2.associate_route_table(private_route_table, private_subnet))
234
+ end
235
+ end
236
+ end
237
+
238
+ Contract None => ArrayOf[String]
239
+ def subnets
240
+ [public_subnet, private_subnet]
241
+ end
242
+
243
+ Contract None => Bool
244
+ def enable_public_ips
245
+ ec2.map_public_ip_on_launch?(public_subnet) || ec2.map_public_ip_on_launch(public_subnet, true)
246
+ end
247
+
248
+ Contract None => String
249
+ def vpc
250
+ find_vpc || create_vpc
251
+ end
252
+
253
+ Contract None => Bool
254
+ def enable_dns_support
255
+ ec2.vpc_supports_dns?(vpc) || ec2.enable_dns_support(vpc)
256
+ end
257
+
258
+ Contract None => Bool
259
+ def enable_dns_hostnames
260
+ ec2.vpc_supports_dns_hostnames?(vpc) || ec2.enable_dns_hostnames(vpc)
261
+ end
262
+
263
+ Contract None => String
264
+ def create_jumpbox
265
+ upload_ssh_key
266
+
267
+ cache.store(:jumpbox_id, ec2.create_instance(
268
+ image_id: ami,
269
+ instance_type: config.instance_type,
270
+ key_name: bootstrap_tag,
271
+ client_token: Digest::SHA256.hexdigest(bootstrap_tag),
272
+ network_interfaces: [{
273
+ device_index: 0,
274
+ subnet_id: public_subnet,
275
+ associate_public_ip_address: true,
276
+ groups: [jumpbox_security_group]
277
+ }]
278
+ ).instance_id).tap do |instance_id|
279
+ ec2.assign_name bootstrap_tag, instance_id
280
+ end
281
+ end
282
+
283
+ Contract None => Maybe[String]
284
+ def find_jumpbox
285
+ ENV.fetch('BOOTSTRAP_JUMPBOX_ID') do
286
+ cache.fetch(:jumpbox_id) do
287
+ ec2
288
+ .tagged(type: 'instance', value: bootstrap_tag)
289
+ .map(&:resource_id)
290
+ .first
291
+ end
292
+ end
293
+ end
294
+
295
+ Contract None => String
296
+ def jumpbox
297
+ find_jumpbox || create_jumpbox
298
+ end
299
+
300
+ Contract None => Bool
301
+ def tag_jumpbox
302
+ ec2.create_tags([jumpbox], [{ key: 'Cloudstrapped', value: 'true' }])
303
+ end
304
+
305
+ Contract None => String
306
+ def ami
307
+ @ami ||= ENV.fetch('BOOTSTRAP_AMI') do
308
+ cache.fetch(:ami_id) do
309
+ cache.store :ami_id, ec2.latest_ubuntu(config.ubuntu_release).image_id
310
+ end
311
+ end
312
+ end
313
+
314
+ Contract None => String
315
+ def upload_ssh_key
316
+ ec2.import_key_pair bootstrap_tag, ssh_key.to_s # TODO: Cache this.
317
+ end
318
+
319
+ Contract None => SSH::Key
320
+ def ssh_key
321
+ @ssh_key ||= SSH::Key.new bootstrap_tag
322
+ end
323
+
324
+ Contract None => String
325
+ def bootstrap_tag
326
+ @bootstrap_tag ||= ENV.fetch('BOOTSTRAP_TAG') do
327
+ "lkg@#{username}/#{uuid}"
328
+ end
329
+ end
330
+
331
+ Contract None => String
332
+ def username
333
+ @username ||= ENV.fetch('BOOTSTRAP_USERNAME') do
334
+ cache.fetch(:username) do
335
+ cache.store(:username, iam.user.user_name)
336
+ end
337
+ end
338
+ end
339
+
340
+ Contract None => String
341
+ def uuid
342
+ @uuid ||= ENV.fetch('BOOTSTRAP_UUID') do
343
+ cache.fetch(:uuid) do
344
+ cache.store(:uuid, SecureRandom.uuid)
345
+ end
346
+ end
347
+ end
348
+
349
+ Contract None => String
350
+ def public_availability_zone
351
+ @public_availability_zone ||= ENV.fetch('BOOTSTRAP_PUBLIC_AVAILABILITY_ZONE') do
352
+ cache.fetch(:public_availability_zone) do
353
+ cache.store(:public_availability_zone, ec2
354
+ .subnets
355
+ .select { |subnet| subnet.subnet_id == public_subnet }
356
+ .map { |subnet| subnet.availability_zone }
357
+ .first)
358
+ end
359
+ end
360
+ end
361
+
362
+ Contract None => String
363
+ def private_availability_zone
364
+ @private_availability_zone ||= ENV.fetch('BOOTSTRAP_PRIVATE_AVAILABILITY_ZONE') do
365
+ cache.fetch(:private_availability_zone) do
366
+ cache.store(:private_availability_zone, ec2
367
+ .subnets
368
+ .select { |subnet| subnet.subnet_id == private_subnet }
369
+ .map { |subnet| subnet.availability_zone }
370
+ .first)
371
+ end
372
+ end
373
+ end
374
+
375
+ Contract None => String
376
+ def jumpbox_ip
377
+ @jumpbox_ip ||= ENV.fetch('BOOTSTRAP_JUMPBOX_IP') do
378
+ cache.fetch(:jumpbox_ip) do
379
+ cache.store(:jumpbox_ip, ec2
380
+ .instances
381
+ .select { |instance| instance.instance_id == jumpbox }
382
+ .flat_map(&:network_interfaces)
383
+ .map(&:association)
384
+ .map(&:public_ip)
385
+ .first)
386
+ end
387
+ end
388
+ end
389
+
390
+ Contract None => Bool
391
+ def configure_hdp
392
+ bootstrap_properties
393
+ .define('Provider', 'AWS')
394
+ .define('KeepTerraform', 'true')
395
+ .define('AWS.NodeInstanceType', config.node_instance_type)
396
+ .define('AWS.MasterInstanceType', config.master_instance_type)
397
+ .define('AWS.GlusterFSInstanceType', config.gluster_instance_type)
398
+ .define('NodeCount', config.node_count)
399
+ .define('MasterCount', config.master_count)
400
+ .define('GlusterNodeCount', config.gluster_count)
401
+ .define('AWS.Region', config.region)
402
+ .define('AWS.AvailabilityZones', public_availability_zone)
403
+ .define('AWS.PublicSubnetIDsAndAZ', [public_subnet, public_availability_zone].join(':'))
404
+ .define('AWS.PrivateSubnetIDsAndAZ', [private_subnet, private_availability_zone].join(':'))
405
+ .define('AWS.Keypair', bootstrap_tag)
406
+ .define('AWS.KeypairFile', '/home/ubuntu/.ssh/id_rsa')
407
+ .define('AWS.JumpboxCIDR', '0.0.0.0/0')
408
+ .define('AWS.VPCID', vpc)
409
+ .define('AWS.LinuxAMI', ami)
410
+ .define('HCPDomainName', config.domain_name)
411
+ .save!
412
+ end
413
+
414
+ Contract None => Bool
415
+ def jumpbox_running?
416
+ ec2
417
+ .instances
418
+ .select { |instance| instance.instance_id == jumpbox }
419
+ .map { |instance| instance.state.name }
420
+ .first == 'running'
421
+ end
422
+
423
+ Contract None => Any
424
+ def configure_jumpbox
425
+ private_key = ssh_key.private_file
426
+ properties = bootstrap_properties.file
427
+ package = config.hdp_package_url
428
+
429
+ ssh.to(jumpbox_ip) do
430
+ '/home/ubuntu/.ssh/id_rsa'.tap do |target|
431
+ execute :rm, '-f', target
432
+ upload! private_key, target
433
+ execute :chmod, '-w', target
434
+ end
435
+
436
+ upload! properties, '/home/ubuntu/bootstrap.properties'
437
+
438
+ as :root do
439
+ execute :apt, *%w(install --assume-yes genisoimage aria2)
440
+ execute :rm, '-f', '/opt/bootstrap.deb'
441
+ execute :aria2c, '--continue=true', '--dir=/opt', '--out=bootstrap.deb', package
442
+ execute :dpkg, *%w(--install /opt/bootstrap.deb)
443
+ end
444
+ end
445
+ end
446
+
447
+ Contract None => Bool
448
+ def requires_human_oversight?
449
+ ['false', 'nil', nil].include? ENV['BOOTSTRAP_WITHOUT_HUMAN_OVERSIGHT']
450
+ end
451
+
452
+ Contract None => Any
453
+ def launch
454
+ return false if requires_human_oversight?
455
+
456
+ access_key_id = ec2.api.config.credentials.credentials.access_key_id
457
+ secret_access_key = ec2.api.config.credentials.credentials.secret_access_key
458
+
459
+ ssh.to(jumpbox_ip) do
460
+ with(aws_access_key_id: access_key_id, aws_secret_access_key: secret_access_key) do
461
+ execute :bootstrap, *%w(install bootstrap.properties)
462
+ end
463
+ end
464
+ end
465
+
466
+ private
467
+
468
+ Contract None => SSH::Client
469
+ def ssh
470
+ @ssh ||= SSH::Client.new(ssh_key.private_file)
471
+ end
472
+
473
+ Contract None => HDP::BootstrapProperties
474
+ def bootstrap_properties
475
+ @hdp ||= HDP::BootstrapProperties.new
476
+ end
477
+
478
+ Contract None => Amazon::EC2
479
+ def ec2
480
+ @ec2 ||= Amazon::EC2.new
481
+ end
482
+
483
+ Contract None => Amazon::IAM
484
+ def iam
485
+ @iam ||= Amazon::IAM.new
486
+ end
487
+
488
+ Contract None => Config
489
+ def config
490
+ @config ||= Config.new
491
+ end
492
+
493
+ Contract None => Moneta::Proxy
494
+ def cache
495
+ @cache ||= Moneta.new :File, dir: config.cache_path
496
+ end
497
+ end
498
+ end
@@ -1,498 +1,6 @@
1
- require 'contracts'
2
- require 'moneta'
3
- require 'securerandom'
4
-
5
- require_relative 'amazon'
6
- require_relative 'config'
7
- require_relative 'errors'
8
- require_relative 'hdp/bootstrap_properties'
9
- require_relative 'ssh'
1
+ require_relative 'agent'
10
2
 
11
3
  module Cloudstrap
12
- class BootstrapAgent
13
- include ::Contracts::Core
14
- include ::Contracts::Builtin
15
-
16
- Contract None => BootstrapAgent
17
- def initialize
18
- validate_configuration!
19
- self
20
- end
21
-
22
- Contract None => Any
23
- def validate_configuration! # TODO: Does this really belong in BootstrapAgent?
24
- return if ec2.valid_region?(config.region)
25
- raise ::Cloudstrap::ConfigurationError, "Region #{config.region} is not valid"
26
- end
27
-
28
- Contract None => String
29
- def create_vpc
30
- cache.store(:vpc_id, ec2.create_vpc.vpc_id).tap do |vpc_id|
31
- ec2.assign_name(bootstrap_tag, vpc_id)
32
- end
33
- end
34
-
35
- Contract None => Maybe[String]
36
- def find_vpc
37
- ENV.fetch('BOOTSTRAP_VPC_ID') do
38
- cache.fetch(:vpc_id) do
39
- cache.store :vpc_id, ec2
40
- .tagged(type: 'vpc', value: bootstrap_tag)
41
- .map(&:resource_id)
42
- .first
43
- end
44
- end
45
- end
46
-
47
- Contract None => String
48
- def internet_gateway
49
- find_internet_gateway || create_internet_gateway
50
- end
51
-
52
- Contract None => String
53
- def create_internet_gateway
54
- cache.store(:internet_gateway_id,
55
- ec2.create_internet_gateway.internet_gateway_id
56
- ).tap { |internet_gateway_id| ec2.assign_name bootstrap_tag, internet_gateway_id }
57
- end
58
-
59
- Contract None => String
60
- def nat_gateway_ip_allocation
61
- ENV.fetch('BOOTSTRAP_NAT_GATEWAY_ALLOCATION_ID') do
62
- cache.fetch(:nat_gateway_allocation_id) do # TODO: Simplify this.
63
- id = ec2
64
- .nat_gateways
65
- .select { |nat_gateway| nat_gateway.vpc_id == vpc }
66
- .flat_map { |nat_gateway| nat_gateway.nat_gateway_addresses.map { |address| address.allocation_id } }
67
- .first || ec2.unassociated_address || ec2.create_address
68
- cache.store(:nat_gateway_allocation_id, id)
69
- end
70
- end
71
- end
72
-
73
- Contract None => Maybe[String]
74
- def find_nat_gateway
75
- ec2
76
- .nat_gateways
77
- .select { |nat_gateway| nat_gateway.vpc_id == vpc }
78
- .reject { |nat_gateway| %w(failed deleted).include? nat_gateway.state }
79
- .map { |nat_gateway| nat_gateway.nat_gateway_id }
80
- .first
81
- end
82
-
83
- Contract None => String
84
- def create_nat_gateway
85
- attach_gateway unless ec2.internet_gateway_attached?(internet_gateway, vpc)
86
- ec2.create_nat_gateway(public_subnet, nat_gateway_ip_allocation).nat_gateway_id
87
- end
88
-
89
- Contract None => String
90
- def nat_gateway
91
- ENV.fetch('BOOTSTRAP_NAT_GATEWAY_ID') do
92
- cache.fetch(:nat_gateway_id) do
93
- cache.store(:nat_gateway_id, (find_nat_gateway || create_nat_gateway))
94
- end
95
- end
96
- end
97
-
98
- Contract None => Maybe[String]
99
- def find_internet_gateway
100
- ENV.fetch('BOOTSTRAP_INTERNET_GATEWAY_ID') do
101
- cache.fetch(:internet_gateway_id) do
102
- find_tagged_internet_gateway || find_internet_gateway_for_vpc
103
- end
104
- end
105
- end
106
-
107
- Contract None => Maybe[String]
108
- def find_tagged_internet_gateway
109
- ec2
110
- .tagged(type: 'internet-gateway', value: bootstrap_tag)
111
- .map { |resource| resource.resource.id }
112
- .first
113
- end
114
-
115
- Contract None => Maybe[String]
116
- def find_internet_gateway_for_vpc
117
- ec2
118
- .internet_gateways
119
- .select { |gateway| gateway.attachments.any? { |attachment| attachment.vpc_id == vpc } }
120
- .map { |gateway| gateway.internet_gateway_id }
121
- .first
122
- end
123
-
124
- Contract None => String
125
- def create_jumpbox_security_group
126
- cache.store(:jumpbox_security_group, ec2.create_security_group(:jumpbox, vpc)).tap do |sg|
127
- ec2.assign_name(bootstrap_tag, sg)
128
- end
129
- end
130
-
131
- Contract None => Maybe[String]
132
- def find_jumpbox_security_group
133
- @jumpbox_security_group ||= ENV.fetch('BOOTSTRAP_JUMPBOX_SECURITY_GROUP') do
134
- cache.fetch(:jumpbox_security_group) do
135
- cache.store :jumpbox_security_group, ec2
136
- .tagged(type: 'security-group', value: bootstrap_tag)
137
- .map(&:resource_id)
138
- .first
139
- end
140
- end
141
- end
142
-
143
- Contract None => Bool
144
- def allow_ssh
145
- ec2.authorize_security_group_ingress :tcp, 22, '0.0.0.0/0', jumpbox_security_group
146
- end
147
-
148
- Contract None => String
149
- def jumpbox_security_group
150
- find_jumpbox_security_group || create_jumpbox_security_group
151
- end
152
-
153
- Contract None => String
154
- def private_subnet
155
- @private_subnet ||= ENV.fetch('BOOTSTRAP_PRIVATE_SUBNET_ID') do
156
- cache.fetch(:private_subnet_id) do
157
- properties = { vpc_id: vpc, cidr_block: config.private_cidr_block }
158
- cache.store(:private_subnet_id, (ec2.subnet(properties) || ec2.create_subnet(properties)).tap do |subnet|
159
- ec2.assign_name bootstrap_tag, subnet.subnet_id unless subnet.tags.any? do |tag|
160
- tag.key == 'Name' && tag.value = bootstrap_tag
161
- end
162
- end.subnet_id)
163
- end
164
- end
165
- end
166
-
167
- Contract None => String
168
- def public_subnet
169
- @public_subnet ||= ENV.fetch('BOOTSTRAP_PUBLIC_SUBNET_ID') do
170
- cache.fetch(:public_subnet_id) do
171
- properties = { vpc_id: vpc, cidr_block: config.public_cidr_block }
172
- cache.store(:public_subnet_id, (ec2.subnet(properties) || ec2.create_subnet(properties)).tap do |subnet|
173
- ec2.assign_name bootstrap_tag, subnet.subnet_id unless subnet.tags.any? do |tag|
174
- tag.key == 'Name' && tag.value = bootstrap_tag
175
- end
176
- end.subnet_id)
177
- end
178
- end
179
- end
180
-
181
- Contract None => String
182
- def route_table
183
- @route_table ||= ENV.fetch('BOOTSTRAP_ROUTE_TABLE_ID') do
184
- cache.fetch(:route_table_id) do
185
- cache.store(:route_table_id, ec2
186
- .route_tables
187
- .select { |route_table| route_table.vpc_id == vpc }
188
- .select { |route_table| route_table.associations.any? { |association| association.main } }
189
- .map { |route_table| route_table.route_table_id }
190
- .first).tap do |route_table_id|
191
- ec2.assign_name bootstrap_tag, route_table_id
192
- end
193
- end
194
- end
195
- end
196
-
197
- Contract None => String
198
- def private_route_table
199
- @private_route_table ||= ENV.fetch('BOOTSTRAP_PRIVATE_ROUTE_TABLE_ID') do
200
- cache.fetch(:private_route_table_id) do
201
- id = ec2
202
- .route_tables
203
- .select { |route_table| route_table.vpc_id == vpc }
204
- .reject { |route_table| route_table.associations.any? { |association| association.main } }
205
- .map { |route_table| route_table.route_table_id }
206
- .first || ec2.create_route_table(vpc).route_table_id
207
- cache.store(:private_route_table_id, id).tap do |private_route_table_id|
208
- ec2.assign_name bootstrap_tag, private_route_table_id
209
- end
210
- end
211
- end
212
- end
213
-
214
- Contract None => Bool
215
- def attach_gateway
216
- ec2.attach_internet_gateway internet_gateway, vpc # TODO: Cache this
217
- end
218
-
219
- Contract None => Bool
220
- def default_route
221
- ec2.create_route('0.0.0.0/0', internet_gateway, route_table) # TODO: Cache this
222
- end
223
-
224
- Contract None => Bool
225
- def nat_route
226
- ec2.create_route('0.0.0.0/0', nat_gateway, private_route_table) # TODO: Cache this
227
- end
228
-
229
- Contract None => String
230
- def nat_route_association
231
- @nat_route_association || ENV.fetch('BOOTSTRAP_NAT_ROUTE_ASSOCIATION_ID') do
232
- cache.fetch(:nat_route_association_id) do
233
- cache.store(:nat_route_association_id, ec2.associate_route_table(private_route_table, private_subnet))
234
- end
235
- end
236
- end
237
-
238
- Contract None => ArrayOf[String]
239
- def subnets
240
- [public_subnet, private_subnet]
241
- end
242
-
243
- Contract None => Bool
244
- def enable_public_ips
245
- ec2.map_public_ip_on_launch?(public_subnet) || ec2.map_public_ip_on_launch(public_subnet, true)
246
- end
247
-
248
- Contract None => String
249
- def vpc
250
- find_vpc || create_vpc
251
- end
252
-
253
- Contract None => Bool
254
- def enable_dns_support
255
- ec2.vpc_supports_dns?(vpc) || ec2.enable_dns_support(vpc)
256
- end
257
-
258
- Contract None => Bool
259
- def enable_dns_hostnames
260
- ec2.vpc_supports_dns_hostnames?(vpc) || ec2.enable_dns_hostnames(vpc)
261
- end
262
-
263
- Contract None => String
264
- def create_jumpbox
265
- upload_ssh_key
266
-
267
- cache.store(:jumpbox_id, ec2.create_instance(
268
- image_id: ami,
269
- instance_type: config.instance_type,
270
- key_name: bootstrap_tag,
271
- client_token: Digest::SHA256.hexdigest(bootstrap_tag),
272
- network_interfaces: [{
273
- device_index: 0,
274
- subnet_id: public_subnet,
275
- associate_public_ip_address: true,
276
- groups: [jumpbox_security_group]
277
- }]
278
- ).instance_id).tap do |instance_id|
279
- ec2.assign_name bootstrap_tag, instance_id
280
- end
281
- end
282
-
283
- Contract None => Maybe[String]
284
- def find_jumpbox
285
- ENV.fetch('BOOTSTRAP_JUMPBOX_ID') do
286
- cache.fetch(:jumpbox_id) do
287
- ec2
288
- .tagged(type: 'instance', value: bootstrap_tag)
289
- .map(&:resource_id)
290
- .first
291
- end
292
- end
293
- end
294
-
295
- Contract None => String
296
- def jumpbox
297
- find_jumpbox || create_jumpbox
298
- end
299
-
300
- Contract None => Bool
301
- def tag_jumpbox
302
- ec2.create_tags([jumpbox], [{ key: 'Cloudstrapped', value: 'true' }])
303
- end
304
-
305
- Contract None => String
306
- def ami
307
- @ami ||= ENV.fetch('BOOTSTRAP_AMI') do
308
- cache.fetch(:ami_id) do
309
- cache.store :ami_id, ec2.latest_ubuntu(config.ubuntu_release).image_id
310
- end
311
- end
312
- end
313
-
314
- Contract None => String
315
- def upload_ssh_key
316
- ec2.import_key_pair bootstrap_tag, ssh_key.to_s # TODO: Cache this.
317
- end
318
-
319
- Contract None => SSH::Key
320
- def ssh_key
321
- @ssh_key ||= SSH::Key.new bootstrap_tag
322
- end
323
-
324
- Contract None => String
325
- def bootstrap_tag
326
- @bootstrap_tag ||= ENV.fetch('BOOTSTRAP_TAG') do
327
- "lkg@#{username}/#{uuid}"
328
- end
329
- end
330
-
331
- Contract None => String
332
- def username
333
- @username ||= ENV.fetch('BOOTSTRAP_USERNAME') do
334
- cache.fetch(:username) do
335
- cache.store(:username, iam.user.user_name)
336
- end
337
- end
338
- end
339
-
340
- Contract None => String
341
- def uuid
342
- @uuid ||= ENV.fetch('BOOTSTRAP_UUID') do
343
- cache.fetch(:uuid) do
344
- cache.store(:uuid, SecureRandom.uuid)
345
- end
346
- end
347
- end
348
-
349
- Contract None => String
350
- def public_availability_zone
351
- @public_availability_zone ||= ENV.fetch('BOOTSTRAP_PUBLIC_AVAILABILITY_ZONE') do
352
- cache.fetch(:public_availability_zone) do
353
- cache.store(:public_availability_zone, ec2
354
- .subnets
355
- .select { |subnet| subnet.subnet_id == public_subnet }
356
- .map { |subnet| subnet.availability_zone }
357
- .first)
358
- end
359
- end
360
- end
361
-
362
- Contract None => String
363
- def private_availability_zone
364
- @private_availability_zone ||= ENV.fetch('BOOTSTRAP_PRIVATE_AVAILABILITY_ZONE') do
365
- cache.fetch(:private_availability_zone) do
366
- cache.store(:private_availability_zone, ec2
367
- .subnets
368
- .select { |subnet| subnet.subnet_id == private_subnet }
369
- .map { |subnet| subnet.availability_zone }
370
- .first)
371
- end
372
- end
373
- end
374
-
375
- Contract None => String
376
- def jumpbox_ip
377
- @jumpbox_ip ||= ENV.fetch('BOOTSTRAP_JUMPBOX_IP') do
378
- cache.fetch(:jumpbox_ip) do
379
- cache.store(:jumpbox_ip, ec2
380
- .instances
381
- .select { |instance| instance.instance_id == jumpbox }
382
- .flat_map(&:network_interfaces)
383
- .map(&:association)
384
- .map(&:public_ip)
385
- .first)
386
- end
387
- end
388
- end
389
-
390
- Contract None => Bool
391
- def configure_hdp
392
- bootstrap_properties
393
- .define('Provider', 'AWS')
394
- .define('KeepTerraform', 'true')
395
- .define('AWS.NodeInstanceType', config.node_instance_type)
396
- .define('AWS.MasterInstanceType', config.master_instance_type)
397
- .define('AWS.GlusterFSInstanceType', config.gluster_instance_type)
398
- .define('NodeCount', config.node_count)
399
- .define('MasterCount', config.master_count)
400
- .define('GlusterNodeCount', config.gluster_count)
401
- .define('AWS.Region', config.region)
402
- .define('AWS.AvailabilityZones', public_availability_zone)
403
- .define('AWS.PublicSubnetIDsAndAZ', [public_subnet, public_availability_zone].join(':'))
404
- .define('AWS.PrivateSubnetIDsAndAZ', [private_subnet, private_availability_zone].join(':'))
405
- .define('AWS.Keypair', bootstrap_tag)
406
- .define('AWS.KeypairFile', '/home/ubuntu/.ssh/id_rsa')
407
- .define('AWS.JumpboxCIDR', '0.0.0.0/0')
408
- .define('AWS.VPCID', vpc)
409
- .define('AWS.LinuxAMI', ami)
410
- .define('HCPDomainName', config.domain_name)
411
- .save!
412
- end
413
-
414
- Contract None => Bool
415
- def jumpbox_running?
416
- ec2
417
- .instances
418
- .select { |instance| instance.instance_id == jumpbox }
419
- .map { |instance| instance.state.name }
420
- .first == 'running'
421
- end
422
-
423
- Contract None => Any
424
- def configure_jumpbox
425
- private_key = ssh_key.private_file
426
- properties = bootstrap_properties.file
427
- package = config.hdp_package_url
428
-
429
- ssh.to(jumpbox_ip) do
430
- '/home/ubuntu/.ssh/id_rsa'.tap do |target|
431
- execute :rm, '-f', target
432
- upload! private_key, target
433
- execute :chmod, '-w', target
434
- end
435
-
436
- upload! properties, '/home/ubuntu/bootstrap.properties'
437
-
438
- as :root do
439
- execute :apt, *%w(install --assume-yes genisoimage aria2)
440
- execute :rm, '-f', '/opt/bootstrap.deb'
441
- execute :aria2c, '--continue=true', '--dir=/opt', '--out=bootstrap.deb', package
442
- execute :dpkg, *%w(--install /opt/bootstrap.deb)
443
- end
444
- end
445
- end
446
-
447
- Contract None => Bool
448
- def requires_human_oversight?
449
- ['false', 'nil', nil].include? ENV['BOOTSTRAP_WITHOUT_HUMAN_OVERSIGHT']
450
- end
451
-
452
- Contract None => Any
453
- def launch
454
- return false if requires_human_oversight?
455
-
456
- access_key_id = ec2.api.config.credentials.credentials.access_key_id
457
- secret_access_key = ec2.api.config.credentials.credentials.secret_access_key
458
-
459
- ssh.to(jumpbox_ip) do
460
- with(aws_access_key_id: access_key_id, aws_secret_access_key: secret_access_key) do
461
- execute :bootstrap, *%w(install bootstrap.properties)
462
- end
463
- end
464
- end
465
-
466
- private
467
-
468
- Contract None => SSH::Client
469
- def ssh
470
- @ssh ||= SSH::Client.new(ssh_key.private_file)
471
- end
472
-
473
- Contract None => HDP::BootstrapProperties
474
- def bootstrap_properties
475
- @hdp ||= HDP::BootstrapProperties.new
476
- end
477
-
478
- Contract None => Amazon::EC2
479
- def ec2
480
- @ec2 ||= Amazon::EC2.new
481
- end
482
-
483
- Contract None => Amazon::IAM
484
- def iam
485
- @iam ||= Amazon::IAM.new
486
- end
487
-
488
- Contract None => Config
489
- def config
490
- @config ||= Config.new
491
- end
492
-
493
- Contract None => Moneta::Proxy
494
- def cache
495
- @cache ||= Moneta.new :File, dir: config.cache_path
496
- end
4
+ class BootstrapAgent < Agent
497
5
  end
498
6
  end
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.38.17.pre
4
+ version: 0.38.18.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-08 00:00:00.000000000 Z
11
+ date: 2016-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -245,6 +245,7 @@ files:
245
245
  - bin/cloudstrap-dns
246
246
  - cloudstrap.gemspec
247
247
  - lib/cloudstrap.rb
248
+ - lib/cloudstrap/agent.rb
248
249
  - lib/cloudstrap/amazon.rb
249
250
  - lib/cloudstrap/amazon/ec2.rb
250
251
  - lib/cloudstrap/amazon/elb.rb