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