cloudstrap 0.38.17.pre → 0.38.18.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: 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