stemcell 0.12.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +2 -1
- data/CHANGELOG.md +16 -0
- data/README.md +2 -2
- data/examples/stemcell.json +6 -2
- data/lib/stemcell/command_line.rb +1 -0
- data/lib/stemcell/launcher.rb +83 -200
- data/lib/stemcell/metadata_launcher.rb +1 -0
- data/lib/stemcell/metadata_source/configuration.rb +2 -2
- data/lib/stemcell/metadata_source.rb +6 -1
- data/lib/stemcell/option_parser.rb +22 -29
- data/lib/stemcell/templates/bootstrap.sh.erb +91 -20
- data/lib/stemcell/version.rb +1 -1
- data/spec/fixtures/chef_repo/stemcell-azs-missing.json +3 -1
- data/spec/fixtures/chef_repo/stemcell-backing-store-legacy.json +13 -0
- data/spec/fixtures/chef_repo/stemcell-cookbook-attribute.json +3 -1
- data/spec/fixtures/chef_repo/stemcell-defaults-missing.json +3 -1
- data/spec/fixtures/chef_repo/stemcell-options-parser.json +6 -2
- data/spec/fixtures/chef_repo/stemcell.json +3 -1
- data/spec/lib/stemcell/launcher_spec.rb +110 -123
- data/spec/lib/stemcell/metadata_source/configuration_spec.rb +16 -3
- data/spec/lib/stemcell/metadata_source_spec.rb +2 -1
- data/stemcell.gemspec +5 -2
- metadata +36 -9
- data/bin/necrosis +0 -114
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9942211d9334ce09b4a56299f2bc7e3e903d57eb871a60a8a1228c549e6b1407
|
4
|
+
data.tar.gz: 3e70bbdc1434124922c4be3cfb29e6842d6cda8210a1555fe3c36e4887740a11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c4f0a32c8fe858b23bd3ddbbb30ca752a0b23c0a2782d9fd0cf56d9cda0e344bdaa3c2361b1df9f4d5f5413ca88e15c714c868ee2efaa1b304dd74d248601fdb
|
7
|
+
data.tar.gz: a9fb4751d0fe25b94f4c47785da168a9e0e909464d0354461adc8db5d01487d5ea696ebcbc79e74267b6ccd114a794a5e5d13ed90bd6b831a20c3bb5ae5b4906
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
# 0.13.1
|
2
|
+
- Support for specifying --cpu-options
|
3
|
+
|
4
|
+
# 0.13.0
|
5
|
+
- Migrate to AWS SDK to v3
|
6
|
+
- Drop support for ClassicLink
|
7
|
+
- Removed `necrosis` script
|
8
|
+
|
9
|
+
# 0.12.2
|
10
|
+
- Support for using a custom EC2 endpoint
|
11
|
+
|
12
|
+
# 0.12.1
|
13
|
+
- Add support for Amazon Linux to the default bootstrap script
|
14
|
+
- Allow setting backing_store options per region
|
15
|
+
- Display private ip for launched instances
|
16
|
+
|
1
17
|
# 0.12.0
|
2
18
|
- Require Nokogiri ~> 1.8.2 due to vulnerability CVE-2017-15412
|
3
19
|
- Require ruby version >= 2.1 for Nokogiri compatibility
|
data/README.md
CHANGED
@@ -77,10 +77,10 @@ $ stemcell $your_chef_role --tail
|
|
77
77
|
|
78
78
|
### Terminating:
|
79
79
|
|
80
|
-
To terminate, use the
|
80
|
+
To terminate, use the AWS CLI and pass a space separated list of instance ids:
|
81
81
|
|
82
82
|
```bash
|
83
|
-
$
|
83
|
+
$ aws ec2 terminate-instances --instance-ids i-12345678 i-12345679 i-12345670
|
84
84
|
```
|
85
85
|
|
86
86
|
## Automation ##
|
data/examples/stemcell.json
CHANGED
@@ -9,10 +9,14 @@
|
|
9
9
|
|
10
10
|
"backing_store": {
|
11
11
|
"ebs": {
|
12
|
-
"
|
12
|
+
"us-east-1": {
|
13
|
+
"image_id": "ami-23d9a94a"
|
14
|
+
}
|
13
15
|
},
|
14
16
|
"instance_store": {
|
15
|
-
"
|
17
|
+
"us-east-1": {
|
18
|
+
"image_id": "ami-d9d6a6b0"
|
19
|
+
}
|
16
20
|
}
|
17
21
|
},
|
18
22
|
|
@@ -132,6 +132,7 @@ module Stemcell
|
|
132
132
|
# comma-separated list when presented as defaults.
|
133
133
|
pd['security_groups'] &&= pd['security_groups'].join(',')
|
134
134
|
pd['tags'] &&= pd['tags'].to_a.map { |p| p.join('=') }.join(',')
|
135
|
+
pd['cpu_options'] &&= pd['cpu_options'].to_a.map { |p| p.join('=') }.join(',')
|
135
136
|
pd['chef_cookbook_attributes'] &&= pd['chef_cookbook_attributes'].join(',')
|
136
137
|
end
|
137
138
|
|
data/lib/stemcell/launcher.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require 'aws-sdk-
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'base64'
|
2
3
|
require 'logger'
|
3
4
|
require 'erb'
|
4
5
|
require 'set'
|
@@ -30,6 +31,7 @@ module Stemcell
|
|
30
31
|
'chef_environment',
|
31
32
|
'chef_data_bag_secret',
|
32
33
|
'chef_data_bag_secret_path',
|
34
|
+
'cpu_options',
|
33
35
|
'git_branch',
|
34
36
|
'git_key',
|
35
37
|
'git_origin',
|
@@ -48,7 +50,6 @@ module Stemcell
|
|
48
50
|
'security_groups',
|
49
51
|
'security_group_ids',
|
50
52
|
'tags',
|
51
|
-
'classic_link',
|
52
53
|
'iam_role',
|
53
54
|
'ebs_optimized',
|
54
55
|
'termination_protection',
|
@@ -75,6 +76,7 @@ module Stemcell
|
|
75
76
|
|
76
77
|
@region = opts['region']
|
77
78
|
@vpc_id = opts['vpc_id']
|
79
|
+
@ec2_endpoint = opts['ec2_endpoint']
|
78
80
|
@aws_access_key = opts['aws_access_key']
|
79
81
|
@aws_secret_key = opts['aws_secret_key']
|
80
82
|
@aws_session_token = opts['aws_session_token']
|
@@ -89,7 +91,7 @@ module Stemcell
|
|
89
91
|
opts['git_key'] = try_file(opts['git_key'])
|
90
92
|
opts['chef_data_bag_secret'] = try_file(opts['chef_data_bag_secret'])
|
91
93
|
|
92
|
-
# generate tags and merge in any that were
|
94
|
+
# generate tags and merge in any that were specified as inputs
|
93
95
|
tags = {
|
94
96
|
'Name' => "#{opts['chef_role']}-#{opts['chef_environment']}",
|
95
97
|
'Group' => "#{opts['chef_role']}-#{opts['chef_environment']}",
|
@@ -105,31 +107,38 @@ module Stemcell
|
|
105
107
|
:image_id => opts['image_id'],
|
106
108
|
:instance_type => opts['instance_type'],
|
107
109
|
:key_name => opts['key_name'],
|
108
|
-
:
|
110
|
+
:min_count => opts['count'],
|
111
|
+
:max_count => opts['count'],
|
109
112
|
}
|
110
113
|
|
114
|
+
|
115
|
+
# Associate Public IP can only bet set on network_interfaces, and if present
|
116
|
+
# security groups and subnet should be set on the interface. VPC-only.
|
117
|
+
# Primary network interface
|
118
|
+
network_interface = {
|
119
|
+
device_index: 0,
|
120
|
+
}
|
121
|
+
launch_options[:network_interfaces] = [network_interface]
|
122
|
+
|
111
123
|
if opts['security_group_ids'] && !opts['security_group_ids'].empty?
|
112
|
-
|
124
|
+
network_interface[:groups] = opts['security_group_ids']
|
113
125
|
end
|
114
126
|
|
115
127
|
if opts['security_groups'] && !opts['security_groups'].empty?
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
launch_options[:security_group_ids].concat(security_group_ids)
|
121
|
-
else
|
122
|
-
launch_options[:security_groups] = opts['security_groups']
|
123
|
-
end
|
128
|
+
# convert sg names to sg ids as VPC only accepts ids
|
129
|
+
security_group_ids = get_vpc_security_group_ids(@vpc_id, opts['security_groups'])
|
130
|
+
network_interface[:groups] ||= []
|
131
|
+
network_interface[:groups].concat(security_group_ids)
|
124
132
|
end
|
125
133
|
|
134
|
+
launch_options[:placement] = placement = {}
|
126
135
|
# specify availability zone (optional)
|
127
136
|
if opts['availability_zone']
|
128
|
-
|
137
|
+
placement[:availability_zone] = opts['availability_zone']
|
129
138
|
end
|
130
139
|
|
131
140
|
if opts['subnet']
|
132
|
-
|
141
|
+
network_interface[:subnet_id] = opts['subnet']
|
133
142
|
end
|
134
143
|
|
135
144
|
if opts['private_ip_address']
|
@@ -137,23 +146,23 @@ module Stemcell
|
|
137
146
|
end
|
138
147
|
|
139
148
|
if opts['dedicated_tenancy']
|
140
|
-
|
149
|
+
placement[:tenancy] = 'dedicated'
|
141
150
|
end
|
142
151
|
|
143
152
|
if opts['associate_public_ip_address']
|
144
|
-
|
153
|
+
network_interface[:associate_public_ip_address] = opts['associate_public_ip_address']
|
145
154
|
end
|
146
155
|
|
147
156
|
# specify IAM role (optional)
|
148
157
|
if opts['iam_role']
|
149
|
-
launch_options[:iam_instance_profile] =
|
158
|
+
launch_options[:iam_instance_profile] = {
|
159
|
+
name: opts['iam_role']
|
160
|
+
}
|
150
161
|
end
|
151
162
|
|
152
163
|
# specify placement group (optional)
|
153
164
|
if opts['placement_group']
|
154
|
-
|
155
|
-
:group_name => opts['placement_group'],
|
156
|
-
}
|
165
|
+
placement[:group_name] = opts['placement_group']
|
157
166
|
end
|
158
167
|
|
159
168
|
# specify an EBS-optimized instance (optional)
|
@@ -170,6 +179,11 @@ module Stemcell
|
|
170
179
|
launch_options[:block_device_mappings] = opts['block_device_mappings']
|
171
180
|
end
|
172
181
|
|
182
|
+
# specify cpu options (optional)
|
183
|
+
if opts['cpu_options']
|
184
|
+
launch_options[:cpu_options] = opts['cpu_options']
|
185
|
+
end
|
186
|
+
|
173
187
|
# specify ephemeral block device mappings (optional)
|
174
188
|
if opts['ephemeral_devices']
|
175
189
|
launch_options[:block_device_mappings] ||= []
|
@@ -181,35 +195,31 @@ module Stemcell
|
|
181
195
|
end
|
182
196
|
end
|
183
197
|
|
198
|
+
if opts['termination_protection']
|
199
|
+
launch_options[:disable_api_termination] = true
|
200
|
+
end
|
201
|
+
|
184
202
|
# generate user data script to bootstrap instance, include in launch
|
185
203
|
# options UNLESS we have manually set the user-data (ie. for ec2admin)
|
186
|
-
launch_options[:user_data] = opts.fetch('user_data', render_template(opts))
|
204
|
+
launch_options[:user_data] = Base64.encode64(opts.fetch('user_data', render_template(opts)))
|
205
|
+
|
206
|
+
# add tags to launch options so we don't need to make a separate CreateTags call
|
207
|
+
launch_options[:tag_specifications] = [{
|
208
|
+
resource_type: 'instance',
|
209
|
+
tags: tags.map { |k, v| { key: k, value: v } }
|
210
|
+
}]
|
187
211
|
|
188
212
|
# launch instances
|
189
213
|
instances = do_launch(launch_options)
|
190
214
|
|
191
215
|
# everything from here on out must succeed, or we kill the instances we just launched
|
192
216
|
begin
|
193
|
-
# set tags on all instances launched
|
194
|
-
set_tags(instances, tags)
|
195
|
-
@log.info "sent ec2 api tag requests successfully"
|
196
|
-
|
197
|
-
# link to classiclink
|
198
|
-
unless @vpc_id
|
199
|
-
set_classic_link(instances, opts['classic_link'])
|
200
|
-
@log.info "successfully applied classic link settings (if any)"
|
201
|
-
end
|
202
|
-
|
203
|
-
# turn on termination protection
|
204
|
-
# we do this now to make sure all other settings worked
|
205
|
-
if opts['termination_protection']
|
206
|
-
enable_termination_protection(instances)
|
207
|
-
@log.info "successfully enabled termination protection"
|
208
|
-
end
|
209
|
-
|
210
217
|
# wait for aws to report instance stats
|
211
218
|
if opts.fetch('wait', true)
|
212
|
-
|
219
|
+
instance_ids = instances.map(&:instance_id)
|
220
|
+
@log.info "Waiting up to #{MAX_RUNNING_STATE_WAIT_TIME} seconds for #{instances.count} " \
|
221
|
+
"instance(s): (#{instance_ids})"
|
222
|
+
instances = wait(instance_ids)
|
213
223
|
print_run_info(instances)
|
214
224
|
@log.info "launched instances successfully"
|
215
225
|
end
|
@@ -226,19 +236,18 @@ module Stemcell
|
|
226
236
|
return instances
|
227
237
|
end
|
228
238
|
|
229
|
-
def kill(
|
230
|
-
return if !
|
239
|
+
def kill(instance_ids, opts={})
|
240
|
+
return if !instance_ids || instance_ids.empty?
|
231
241
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
check_errors(:kill, instances.map(&:id), errors)
|
242
|
+
@log.warn "Terminating instances #{instance_ids}"
|
243
|
+
ec2.terminate_instances(instance_ids: instance_ids)
|
244
|
+
nil # nil == success
|
245
|
+
rescue Aws::EC2::Errors::InvalidInstanceIDNotFound => e
|
246
|
+
raise unless opts[:ignore_not_found]
|
247
|
+
|
248
|
+
invalid_ids = e.message.scan(/i-[a-z0-9]+/)
|
249
|
+
instance_ids -= invalid_ids
|
250
|
+
retry unless instance_ids.empty? || invalid_ids.empty? # don't retry if we couldn't find any instance ids
|
242
251
|
end
|
243
252
|
|
244
253
|
# this is made public for ec2admin usage
|
@@ -248,7 +257,7 @@ module Stemcell
|
|
248
257
|
erb_template = ERB.new(template_file)
|
249
258
|
last_bootstrap_line = LAST_BOOTSTRAP_LINE
|
250
259
|
generated_template = erb_template.result(binding)
|
251
|
-
@log.debug "
|
260
|
+
@log.debug "generated template is #{generated_template}"
|
252
261
|
return generated_template
|
253
262
|
end
|
254
263
|
|
@@ -258,22 +267,23 @@ module Stemcell
|
|
258
267
|
puts "\nhere is the info for what's launched:"
|
259
268
|
instances.each do |instance|
|
260
269
|
puts "\tinstance_id: #{instance.instance_id}"
|
261
|
-
puts "\tpublic ip: #{instance.public_ip_address}"
|
270
|
+
puts "\tpublic ip: #{instance.public_ip_address || 'none'}"
|
271
|
+
puts "\tprivate ip: #{instance.private_ip_address || 'none'}"
|
262
272
|
puts
|
263
273
|
end
|
264
274
|
puts "install logs will be in /var/log/init and /var/log/init.err"
|
265
275
|
end
|
266
276
|
|
267
|
-
def wait(
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
277
|
+
def wait(instance_ids)
|
278
|
+
started_at = Time.now
|
279
|
+
result = ec2.wait_until(:instance_running, instance_ids: instance_ids) do |w|
|
280
|
+
w.max_attempts = nil
|
281
|
+
w.delay = RUNNING_STATE_WAIT_SLEEP_TIME
|
282
|
+
w.before_wait do |attempts, response|
|
283
|
+
throw :failure if Time.now - started_at > MAX_RUNNING_STATE_WAIT_TIME
|
284
|
+
end
|
274
285
|
end
|
275
|
-
|
276
|
-
@log.info "all instances in running state"
|
286
|
+
result.map { |page| page.reservations.map(&:instances) }.flatten
|
277
287
|
end
|
278
288
|
|
279
289
|
def verify_required_options(params, required_options)
|
@@ -289,35 +299,22 @@ module Stemcell
|
|
289
299
|
def do_launch(opts={})
|
290
300
|
@log.debug "about to launch instance(s) with options #{opts}"
|
291
301
|
@log.info "launching instances"
|
292
|
-
instances = ec2.
|
293
|
-
instances = [instances] unless Array === instances
|
302
|
+
instances = ec2.run_instances(opts).instances
|
294
303
|
instances.each do |instance|
|
295
304
|
@log.info "launched instance #{instance.instance_id}"
|
296
305
|
end
|
297
306
|
return instances
|
298
307
|
end
|
299
308
|
|
300
|
-
def set_tags(instances=[], tags)
|
301
|
-
@log.info "setting tags on instance(s)"
|
302
|
-
errors = run_batch_operation(instances) do |instance|
|
303
|
-
begin
|
304
|
-
instance.tags.set(tags)
|
305
|
-
nil # nil == success
|
306
|
-
rescue AWS::EC2::Errors::InvalidInstanceID::NotFound => e
|
307
|
-
e
|
308
|
-
end
|
309
|
-
end
|
310
|
-
check_errors(:set_tags, instances.map(&:id), errors)
|
311
|
-
end
|
312
|
-
|
313
309
|
# Resolve security group names to their ids in the given VPC
|
314
310
|
def get_vpc_security_group_ids(vpc_id, group_names)
|
315
311
|
group_map = {}
|
316
312
|
@log.info "resolving security groups #{group_names} in #{vpc_id}"
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
313
|
+
ec2.describe_security_groups(filters: [{ name: 'vpc-id', values: [vpc_id] }]).
|
314
|
+
each do |response|
|
315
|
+
response.security_groups.each do |sg|
|
316
|
+
group_map[sg.group_name] = sg.group_id
|
317
|
+
end
|
321
318
|
end
|
322
319
|
group_ids = []
|
323
320
|
group_names.each do |sg_name|
|
@@ -327,129 +324,15 @@ module Stemcell
|
|
327
324
|
group_ids
|
328
325
|
end
|
329
326
|
|
330
|
-
def set_classic_link(left_to_process, classic_link)
|
331
|
-
return unless classic_link
|
332
|
-
return unless classic_link['vpc_id']
|
333
|
-
|
334
|
-
security_group_ids = classic_link['security_group_ids'] || []
|
335
|
-
security_group_names = classic_link['security_groups'] || []
|
336
|
-
return if security_group_ids.empty? && security_group_names.empty?
|
337
|
-
|
338
|
-
if !security_group_names.empty?
|
339
|
-
extra_group_ids = get_vpc_security_group_ids(classic_link['vpc_id'], security_group_names)
|
340
|
-
security_group_ids = security_group_ids + extra_group_ids
|
341
|
-
end
|
342
|
-
|
343
|
-
@log.info "applying classic link settings on #{left_to_process.count} instance(s)"
|
344
|
-
|
345
|
-
errors = []
|
346
|
-
processed = []
|
347
|
-
times_out_at = Time.now + MAX_RUNNING_STATE_WAIT_TIME
|
348
|
-
until left_to_process.empty?
|
349
|
-
wait_time_expire_or_sleep(times_out_at)
|
350
|
-
|
351
|
-
# we can only apply classic link when instances are in the running state
|
352
|
-
# lets apply classiclink as instances become available so we don't wait longer than necessary
|
353
|
-
recently_running = left_to_process.select{ |inst| inst.status == :running }
|
354
|
-
left_to_process = left_to_process.reject{ |inst| recently_running.include?(inst) }
|
355
|
-
|
356
|
-
processed += recently_running
|
357
|
-
errors += run_batch_operation(recently_running) do |instance|
|
358
|
-
begin
|
359
|
-
result = ec2.client.attach_classic_link_vpc({
|
360
|
-
:instance_id => instance.id,
|
361
|
-
:vpc_id => classic_link['vpc_id'],
|
362
|
-
:groups => security_group_ids,
|
363
|
-
})
|
364
|
-
result.error
|
365
|
-
rescue StandardError => e
|
366
|
-
e
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
check_errors(:set_classic_link, processed.map(&:id), errors)
|
372
|
-
end
|
373
|
-
|
374
|
-
def enable_termination_protection(instances)
|
375
|
-
@log.info "enabling termination protection on instance(s)"
|
376
|
-
errors = run_batch_operation(instances) do |instance|
|
377
|
-
begin
|
378
|
-
resp = ec2.client.modify_instance_attribute({
|
379
|
-
:instance_id => instance.id,
|
380
|
-
:disable_api_termination => {
|
381
|
-
:value => true
|
382
|
-
}
|
383
|
-
})
|
384
|
-
resp.error # returns nil (success) unless there was an error
|
385
|
-
rescue StandardError => e
|
386
|
-
e
|
387
|
-
end
|
388
|
-
end
|
389
|
-
check_errors(:enable_termination_protection, instances.map(&:id), errors)
|
390
|
-
end
|
391
|
-
|
392
327
|
# attempt to accept keys as file paths
|
393
328
|
def try_file(opt="")
|
394
329
|
File.read(File.expand_path(opt)) rescue opt
|
395
330
|
end
|
396
331
|
|
397
|
-
INITIAL_RETRY_SEC = 1
|
398
|
-
|
399
|
-
# Return a Hash of instance => error. Empty hash indicates "no error"
|
400
|
-
# for code block:
|
401
|
-
# - if block returns nil, success
|
402
|
-
# - if block returns non-nil value (e.g., exception), retry 3 times w/ backoff
|
403
|
-
# - if block raises exception, fail
|
404
|
-
def run_batch_operation(instances)
|
405
|
-
instances.map do |instance|
|
406
|
-
begin
|
407
|
-
attempt = 0
|
408
|
-
result = nil
|
409
|
-
while attempt < @max_attempts
|
410
|
-
# sleep idempotently except for the first attempt
|
411
|
-
sleep(INITIAL_RETRY_SEC * 2 ** attempt) if attempt != 0
|
412
|
-
result = yield(instance)
|
413
|
-
break if result.nil? # nil indicates success
|
414
|
-
attempt += 1
|
415
|
-
end
|
416
|
-
result # result for this instance is nil or returned exception
|
417
|
-
rescue => e
|
418
|
-
e # result for this instance is caught exception
|
419
|
-
end
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
def check_errors(operation, instance_ids, errors)
|
424
|
-
return if errors.all?(&:nil?)
|
425
|
-
raise IncompleteOperation.new(
|
426
|
-
operation,
|
427
|
-
instance_ids,
|
428
|
-
instance_ids.zip(errors).reject { |i, e| e.nil? }
|
429
|
-
)
|
430
|
-
end
|
431
|
-
|
432
332
|
def ec2
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
ec2_url = "ec2.#{@region}.amazonaws.com"
|
437
|
-
|
438
|
-
if @vpc_id
|
439
|
-
@ec2 = AWS::EC2::VPC.new(@vpc_id, :ec2_endpoint => ec2_url)
|
440
|
-
else
|
441
|
-
@ec2 = AWS::EC2.new(:ec2_endpoint => ec2_url)
|
442
|
-
end
|
443
|
-
|
444
|
-
@ec2
|
445
|
-
end
|
446
|
-
|
447
|
-
def wait_time_expire_or_sleep(times_out_at)
|
448
|
-
now = Time.now
|
449
|
-
if now >= times_out_at
|
450
|
-
raise TimeoutError, "exceded timeout of #{MAX_RUNNING_STATE_WAIT_TIME} seconds"
|
451
|
-
else
|
452
|
-
sleep [RUNNING_STATE_WAIT_SLEEP_TIME, times_out_at - now].min
|
333
|
+
@ec2 ||= begin
|
334
|
+
opts = @ec2_endpoint ? { endpoint: @ec2_endpoint } : {}
|
335
|
+
Aws::EC2::Client.new(opts)
|
453
336
|
end
|
454
337
|
end
|
455
338
|
|
@@ -463,7 +346,7 @@ module Stemcell
|
|
463
346
|
aws_configs.merge!({
|
464
347
|
:session_token => @aws_session_token,
|
465
348
|
}) if @aws_session_token
|
466
|
-
|
349
|
+
Aws.config.update(aws_configs)
|
467
350
|
end
|
468
351
|
end
|
469
352
|
end
|
@@ -101,6 +101,7 @@ module Stemcell
|
|
101
101
|
'region' => options['region'],
|
102
102
|
'vpc_id' => options['vpc_id'],
|
103
103
|
'max_attempts' => options['batch_operation_retries'],
|
104
|
+
'ec2_endpoint' => options['ec2_endpoint'],
|
104
105
|
})
|
105
106
|
# Slice off just the options used for launching.
|
106
107
|
launch_options = {}
|
@@ -21,10 +21,10 @@ module Stemcell
|
|
21
21
|
validate_configutation
|
22
22
|
end
|
23
23
|
|
24
|
-
def options_for_backing_store(backing_store)
|
24
|
+
def options_for_backing_store(backing_store, region)
|
25
25
|
options = backing_store_options[backing_store]
|
26
26
|
raise UnknownBackingStoreError.new(backing_store) if options.nil?
|
27
|
-
options
|
27
|
+
options.fetch(region, options)
|
28
28
|
end
|
29
29
|
|
30
30
|
def random_az_for_region(region)
|
@@ -84,9 +84,14 @@ module Stemcell
|
|
84
84
|
backing_store ||= config.default_options['backing_store']
|
85
85
|
backing_store ||= DEFAULT_BACKING_STORE
|
86
86
|
|
87
|
+
backing_store_region = override_options['region']
|
88
|
+
backing_store_region ||= role_options.to_hash['region'] if role_options
|
89
|
+
backing_store_region ||= config.default_options['region']
|
90
|
+
backing_store_region ||= DEFAULT_OPTIONS['region']
|
91
|
+
|
87
92
|
# Step 3: Retrieve the backing store options from the defaults.
|
88
93
|
|
89
|
-
backing_store_options = config.options_for_backing_store(backing_store)
|
94
|
+
backing_store_options = config.options_for_backing_store(backing_store, backing_store_region)
|
90
95
|
backing_store_options['backing_store'] = backing_store
|
91
96
|
|
92
97
|
# Step 4: Merge the options together in priority order.
|
@@ -42,6 +42,12 @@ module Stemcell
|
|
42
42
|
:env => 'AWS_SESSION_TOKEN',
|
43
43
|
:hide => true
|
44
44
|
},
|
45
|
+
{
|
46
|
+
:name => 'ec2_endpoint',
|
47
|
+
:desc => 'EC2 endpoint',
|
48
|
+
:type => String,
|
49
|
+
:env => 'EC2_ENDPOINT',
|
50
|
+
},
|
45
51
|
{
|
46
52
|
:name => 'region',
|
47
53
|
:desc => "ec2 region to launch in",
|
@@ -90,24 +96,6 @@ module Stemcell
|
|
90
96
|
:type => String,
|
91
97
|
:env => 'VPC_ID'
|
92
98
|
},
|
93
|
-
{
|
94
|
-
:name => 'classic_link_vpc_id',
|
95
|
-
:desc => 'VPC ID to which this instance will be classic-linked',
|
96
|
-
:type => String,
|
97
|
-
:env => 'CLASSIC_LINK_VPC_ID',
|
98
|
-
},
|
99
|
-
{
|
100
|
-
:name => 'classic_link_security_group_ids',
|
101
|
-
:desc => 'comma-separated list of security group IDs to link into ClassicLink; not used unless classic_link_vpc_id is set',
|
102
|
-
:type => String,
|
103
|
-
:env => 'CLASSIC_LINK_SECURITY_GROUP_IDS',
|
104
|
-
},
|
105
|
-
{
|
106
|
-
:name => 'classic_link_security_groups',
|
107
|
-
:desc => 'comma-separated list of security groups to link into ClassicLink; not used unless classic_link_vpc_id is set',
|
108
|
-
:type => String,
|
109
|
-
:env => 'CLASSIC_LINK_SECURITY_GROUPS',
|
110
|
-
},
|
111
99
|
{
|
112
100
|
:name => 'subnet',
|
113
101
|
:desc => "VPC subnet for which to launch this instance",
|
@@ -199,6 +187,12 @@ module Stemcell
|
|
199
187
|
:type => String,
|
200
188
|
:env => 'CHEF_DATA_BAG_SECRET_PATH'
|
201
189
|
},
|
190
|
+
{
|
191
|
+
:name => 'cpu_options',
|
192
|
+
:desc => "comma-separated list of cpu option key=value pairs",
|
193
|
+
:type => String,
|
194
|
+
:env => 'CPU_OPTIONS'
|
195
|
+
},
|
202
196
|
{
|
203
197
|
:name => 'chef_role',
|
204
198
|
:desc => "chef role of instance to be launched",
|
@@ -357,6 +351,16 @@ module Stemcell
|
|
357
351
|
options['tags'] = tags
|
358
352
|
end
|
359
353
|
|
354
|
+
# convert cpu_options from comma separated string to ruby hash
|
355
|
+
if options['cpu_options']
|
356
|
+
cpu_options = {}
|
357
|
+
options['cpu_options'].split(',').each do |cpu_opt|
|
358
|
+
key, value = cpu_opt.split('=')
|
359
|
+
cpu_options[key] = value
|
360
|
+
end
|
361
|
+
options['cpu_options'] = cpu_options
|
362
|
+
end
|
363
|
+
|
360
364
|
# parse block_device_mappings to convert it from the standard CLI format
|
361
365
|
# to the EC2 Ruby API format.
|
362
366
|
# All of this is a bit hard to find so here are some docs links to
|
@@ -424,17 +428,6 @@ module Stemcell
|
|
424
428
|
# convert chef_cookbook_attributes from comma separated string to ruby array
|
425
429
|
options['chef_cookbook_attributes'] &&= options['chef_cookbook_attributes'].split(',')
|
426
430
|
|
427
|
-
# format the classic link options
|
428
|
-
if options['classic_link_vpc_id']
|
429
|
-
options['classic_link']['vpc_id'] = options['classic_link_vpc_id']
|
430
|
-
end
|
431
|
-
if options['classic_link_security_group_ids']
|
432
|
-
options['classic_link']['security_group_ids'] = options['classic_link_security_group_ids'].split(',')
|
433
|
-
end
|
434
|
-
if options['classic_link_security_groups']
|
435
|
-
options['classic_link']['security_groups'] = options['classic_link_security_groups'].split(',')
|
436
|
-
end
|
437
|
-
|
438
431
|
options
|
439
432
|
end
|
440
433
|
|